Ivy Wallet 项目中的数据建模最佳实践

Ivy Wallet 项目中的数据建模最佳实践

ivy-wallet Ivy Wallet is an open-source money manager app for android that you can either build or download from Google Play. ivy-wallet 项目地址: https://gitcode.com/gh_mirrors/iv/ivy-wallet

前言

在软件开发中,数据模型的设计直接影响着系统的复杂度和健壮性。本文将结合 Ivy Wallet 项目中的实践经验,深入探讨如何通过合理的数据建模来消除非法状态,提高代码质量。

代数数据类型(ADT)的应用

问题场景

假设我们需要实现一个具有三种状态(加载中、成功、错误)的界面。初学者可能会这样建模:

data class ScreenUiState(
  val content: String?,
  val loading: Boolean,
  val error: String?
)

这种设计存在明显问题:

  • loading=falsecontent=nullerror=null 时,界面应该显示什么?
  • loading=trueerror!=null 时,如何处理?

解决方案:使用密封接口

sealed interface ScreenUiState {
  data object Loading : ScreenUiState
  data class Content(val text: String) : ScreenUiState
  data class Error(val msg: String) : ScreenUiState
}

这种设计优势明显:

  1. 完全消除了非法状态的可能性
  2. 编译时就能捕获类型错误
  3. 代码逻辑更加清晰直观

最佳实践

在 Ivy Wallet 项目中,我们建议:

  • 使用 sealed interface 表示互斥的状态(和类型)
  • 使用 data class 表示复合数据结构(积类型)
  • 可以自由组合这两种类型来精确表达业务领域

显式类型设计

常见问题案例

考虑一个订单模型的初始设计:

data class Order(
  val id: UUID,
  val userId: UUID,
  val itemId: UUID,
  val count: Int,
  val time: LocalDateTime,
  val trackingId: String,
)

这个设计存在多个隐患:

  1. count 可能为0或负数
  2. 不同类型的UUID容易混淆
  3. trackingId 可能为空或包含空格
  4. 时间可能不是UTC格式

改进方案:使用值类和精确类型

data class Order(
  val id: OrderId,
  val user: UserId,
  val item: ItemId,
  val count: PositiveInt,
  val time: Instant,
  val trackingId: NotBlankTrimmedString
)

// 定义各种值类
@JvmInline
value class OrderId(val value: UUID)

@JvmInline
value class UserId(val value: UUID)

@JvmInline
value class PositiveInt private constructor(val value: Int) {
    companion object : Exact<Int, PositiveInt> {
        override val exactName = "PositiveInt"
        override fun Raise<String>.spec(raw: Int): PositiveInt {
            ensure(raw > 0) { "$raw is not > 0" }
            ensure(raw.isFinite()) { "Is not a finite number" }
            return PositiveInt(raw)
        }
    }
}

改进后的优势

  1. 编译时类型安全:不同类型的ID不能互相混淆
  2. 运行时验证PositiveInt 确保数值有效性
  3. 明确语义Instant 强制使用UTC时间
  4. 数据清洁NotBlankTrimmedString 自动处理字符串

实践建议

在 Ivy Wallet 项目中,我们遵循以下原则:

  1. 领域层严格:在核心业务逻辑中使用精确类型
  2. 边界层灵活:在DTO和实体层可以使用原始类型
  3. 尽早验证:在数据进入系统时就进行验证
  4. 类型即文档:通过类型系统表达业务约束

总结

良好的数据建模是构建健壮应用的基础。通过合理使用代数数据类型和显式类型设计,可以:

  • 消除大量非法状态
  • 减少运行时错误
  • 提高代码可读性
  • 简化业务逻辑

Ivy Wallet 项目的实践表明,前期在数据建模上的投入会显著降低后期的维护成本,值得开发者重视。

ivy-wallet Ivy Wallet is an open-source money manager app for android that you can either build or download from Google Play. ivy-wallet 项目地址: https://gitcode.com/gh_mirrors/iv/ivy-wallet

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

宫榕鹃Tobias

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值