编写代码的两种视角

http://tommwq.tech/blog/2020/11/11/201

横看成岭侧成峰,远近高低各不同。不识庐山真面目,只缘身在此山中。

《题西林壁》

从多个的角度观察事物,可以看到不同的现象。对软件来说也是如此。以电子邮件软件为例,从用户角度看,软件是邮箱和邮件。从管理员角度看,软件由账户和邮箱构成。从运维人员的角度看,软件由程序、配置、数据、进程等组成。使用者通过软件执行业务操作,达成业务目标。不同类别的使用者拥有不同的业务目标,执行不同的业务操作。因此在他们眼中,同一个软件有着不同的样子。对于构成软件的模块和对象,也存在着不同的观察视角,4+N视图正是这些视角的体现。不过本文希望讨论的,不是架构或系统层面的视角,而是代码层面的两种视角。

三十辐共一毂,当其无,有车之用。埏埴以为器,当其无,有器之用。凿户牖以为室,当其无,有室之用。故有之以为利,无之以为用。

《道德经》

编写代码有两种常见的视角。一种从代码自身出发,忽略代码所具备的业务含义。这种视角把代码看作一组没有业务含义的变量和函数,一个脱离了业务背景的状态机。

Listing 1: 以软件视角编写的代码

public void login(LoginRequest request, LoginResponse response) {
    String accountType = request.getAccountType();
    String username = request.getUsername();
    String password = request.getPassword();

    boolean success = false;
    if ("baidu".equals(accountType)) {
        success = baiduLogin(username, password);
    } else if ("qq".equals(accountType)) {
        success = qqLogin(username, password);
    } else if ("weibo".equals(accountType)) {
        success = weiboLogin(username, password);
    } else if ("wx".equals(accountType)) {
        success = wxLogin(username, password);
    } else if ("zhifubao".equals(accountType)) {
        success = zhifubaoLogin(username, password);
    } else {
        success = login(username, password);
    }

    response.setResult(success);
}

这样的代码的确实现了业务逻辑,但是可维护性极差。除非你编写的代码是一次性软件,write once, throw it somewhere。对于需要长期支持的,存在需求变更的软件,编写维护性如此之差的代码,其后果往往是缓慢的进度、改不完的bug和天天加班。

这种代码的问题在于把复杂的,具有层次的业务逻辑拍平,导致核心业务逻辑表达不清晰,眉毛胡子一把抓。造成这种情况的原因,通常有业务建模能力不足、程序设计能力不足(比如不熟悉设计模式和重构)等。同时这种代码也反映出开发团队不关注代码质量,不具备开发高质量代码的能力。

另一种编写代码的方法是从业务角度出发。

Listing 2: 以业务视角编写的代码

public void login(LoginRequest request, LoginResponse response) {
    String accountType = request.getAccountType();
    String username = request.getUsername();
    String password = request.getPassword();

    AuthenticationService authService = ServiceManager.getAuthenticationService(accountType);

    response.setResult(authService.authenticate(username, password));
}

这种代码充分表达了业务逻辑,代码的层次既是业务逻辑的层次。代码的可理解性和可维护性好,可以更灵活的应对需求变化,同时缺陷更少。当然,获得这些好处不是没有成本的。以业务视角编写代码,往往需要对业务逻辑和设计模式有更深入的理解,需要花更多的时间对代码进行设计,同时总的代码行数也会增加。那么问题来了,这么做值得吗,得到的好处可以覆盖付出的成本吗?

一个经验原则是,在第三次编写重复代码的时候进行重构。比如上面的例子,如果只支持两种登录方式,采用业务视角编码的成本太高,属于过度设计。如果支持3种或更多登录方式,采用软件视角开发,长期的维护成本太高。

public void login(LoginRequest request, LoginResponse response) {
    String accountType = request.getAccountType();
    String username = request.getUsername();
    String password = request.getPassword();

    boolean success = false;
    if ("baidu".equals(accountType)) {
        success = baiduLogin(username, password);
    } else {
        success = login(username, password);
    }

    response.setResult(success);
}

进一步阅读资料:

  • 实现领域驱动设计
  • 领域驱动开发
  • 从架构角度看什么是好代码
  • 编写可读代码的艺术

猜你喜欢

转载自blog.csdn.net/tq1086/article/details/109633298