一个对象(大到服务,模块,小到类甚至一个字段),都只有一个变更的原因。
电商网站,用户订单的列表页,按最后更新时间排序,这样能把最新的状态在第一页就展示给用户看,避免用户做不必要的翻页操作。
已经有的订单表是这样:
CREATE TABLE order(
id UUID PRIMARY KEY,
data JSONB NOT NULL,
create_time TIMESTAMP NOT NULL,
last_update TIMESTAMP NOT NULL
);
其中,data
中存放订单本身的所有数据,last_update
由触发器在data
发生变化时自动更新。
不难发现,其中last_update
恰恰可以满足需求。于是可以默认以last_update
排序。
last_update
的目的是表达data
字段的最后一次变更时间,其更新是无条件的,有变更就更新。但是从用户角度,并不是所有的更新,都是用户感兴趣的,或是需要用户关心的。使用last_update
来实现这个业务功能,会导致last_update
承载了两个职能:
data
字段本身的最后更新时间。这个时间对于数据同步等功能非常有用。这个时间,是纯技术层面的。与业务无关。尽管在99%的情况下,这两个时间是一样的。但是一但出现不一致的情况,就会给变更带来不必要的麻烦。比如,跑数据库脚本修正数据时,last_udpate
也会被自动更新,但是这种更新,并不是需要被用户感知的。
在存储空间和访问性能都允许的情况下,应当在data
字段内部,引入新的字段来表达唯一的概念。而且确保这个字段只用来处理这一个概念上的问题。
小到一个字段,其含义都应当是明确而且唯一的。
设计一个类,表达不同国家的不同时区。用于在日历软件上给全球用户安排会议时间。需要支持中国、美国和英国的主要城市。如北京、纽约、洛杉矶和伦敦。
enum class TimeZoneOfCountry{
Beijing_CN,
NewYork_US,
LosAngiles_US,
London_UK,
}
显然这个类把两个概念合并到了一起。
在概念和责任上,脱离上下文和业务需要,进行无限分解,甚至创造出概念来把本来一体的东西分解。用实际的场景举例。你在写日志,有人问:“你手上拿到是什么?”你说:“我拿的是一个塑料外壳封装的,内置弹簧自动伸缩的,可由前置滚球装置引导流出的液体油墨储藏器。”但是这个上下文中,别人想听到的只是:“水性笔。”
CSV文件解析