HICSC
探讨一个关于设计的问题?

这两天做新CRM的需求,其实深切的体会到一个系统设计的重要性。对比新旧两版CRM,旧版本在设计上力求最简,不使用太多语言和框架的高级特性,简单直接,但会存在冗余的业务代码;新版本,大量使用语言和框架的高级特性,任何需求在设计上都力求通用。

旧版本胜在简单,只需要你了解大概的业务逻辑,代码瞟两眼就明白什么意思,对代码的修改不会影响到其他逻辑;缺点也显而易见,非常容易造成代码膨胀。

新版本CRM在设计层面,抽象彻底,力求通用,优势是也许能够适应未来快速变化的需求;而缺点也有,反射、AOP、类加载等大量特性的使用,明显会影响系统的性能,面向注解编程的方式,也让代码可读性大大降低。注意,这里我加了一个也许,其实做过业务的同学都知道,想要设计一个非常同样的底层来适应快速变化的需求是相当困难的。除非是,对某个垂直行业的业务有深刻的理解。而大多数时候,都是在摸索中前进。目前公司的通用CRM,上线了第一个版本,涉及到的微服务接近20个,且还在测试阶段,暴露出的问题也不少。因此,我对“好的设计是能够适应未来需求快速变化”这一观点,是持保留态度的。这里面涉及到很多自己的思考,这里不展开,以后再扯。

我一直以来都认为,注解应当仅在技术层面使用,简单来说,就是注解不能涉及业务逻辑,比如:注解用于实现自己的缓存、注解实现数据统计的埋点、注解实现操作日志等等。如果系统中大量使用业务相关的注解,简直就是灾难,一来注解命名不准确,导致接手的人要耗费大量的时间来理解其含义和使用方式,二来需求的频繁变动,导致注解的实现逻辑频繁变更,非常容易出BUG。

比如在新的CRM中,关于权限的注解,我搜了一下,发现有这样几个:

@Auth
@AuthCache
@AuthScene
@AuthSuper
@EnableAuthCache
@EnableCustomAuth

而关于Kafka的注解有:

@EnableCustomConsumerKafka
@EnableCustomDataSyncKafka
@EnableCustomDataSyncPubKafka
@EnableCustomDataSyncSubKafka
@EnableCustomKafka
@EnableCutomProducerKafka
@KafkaMessage

像关于权限的注解,每个注解都有其适用的业务场景,当前看起来也没有任何问题,但如果需求变化,你做的一点点修改,都得考虑是否影响所有的使用场景。

一个简单的解决办法是,在注解中增加属性。对新的需求,使用新的属性,而不去改动老的业务逻辑。慢慢地,你会发现,注解中涉及的属性越来越多,使用注解时要关注的属性也越来越多。目前新的系统刚上线第一版,有的的地方,使用一个注解已经占用三行代码。

这算是面向注解编程的一个缺点吧。真的,每当看到一个类或者方法上面的一排注解时,我都有点欲哭无泪感觉,还有一匹马在心里呼啸而过。

另外一个关于抽象的问题是,对于某个需求,应当抽象到何种程度?

做业务的同学,对于高级搜索应该不陌生,核心就是条件组装起来,扔到数据库查询得出结果。

简单一点,直接把字段、值以及关系拼接成SQL就OK。但也有复杂的方法:

后面一种,明显抽象程度更高,能够更好的适应未来的业务需求。

如果你有维护一个项目几年的经历,你会发现,一旦用户习惯养成,高级搜索的需求在非常长的时间内不会变。

现在再让你来选择两个方案,也许你会选择第一个方案,即接收一个对象,返回一个where字符串,简单明了。

这就是我要表达的意思,对于系统层面抽象是非常有必要的,特别是业务层面的抽象,而像上面我提到的场景,真的没有必要这么麻烦,除非你要做的系统就是一个检索的系统,需要适配各种数据库,需要适用不同的业务场景,那么,像上面那样设计是没有问题的。而在我们系统中,这个功能当前的版本包含40个java文件,相当于一个小的微服务的代码量,在我看来,这是不必要的。

目前,在帮另外一个项目打杂,写着代码,但脑袋里却跑偏了,写下此文,仅用于探讨,而非评判设计好坏,更重要的是想要探讨这个问题:一个系统应当抽象到何种程度?

封面图 by Meriç Dağlı

Comments

Post a Message

人生在世,错别字在所难免,无需纠正。

提交评论