更多笔记

《代码精进之路 从码农到工匠》学习笔记目录

原书:《代码精进之路 从码农到工匠》 | 作者:张建飞

3.7 精简辅助代码

Java 中使用 Optional 优化判空,但 Optional 自身为 null 时也会报 NullPointerException

被嫌弃的代码

1
2
3
4
5
6
7
8
9
if(user !=null){
    Address address = user.getAddress();
    if(address != null){
        PhoneNumber phoneNumber = address.getPhoneNumber();
        if(phoneNumber != null){
            log.info("用户的电话号码={}", phoneNumber.getNumber());
        }
    }
}

消除 if 语句的代码:用户电话号码提取器

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
import java.util.Optional;

public class PhoneNumberExtractor {

    public final static Integer extract(User user) {
        return Optional.ofNullable(user)
                // address 为 null 时,可以返回默认值 0
                .map(User::getAddress).orElse(Optional.empty())
                // phoneNumber 为 null 时,抛出空指针异常
                .flatMap(Address::getPhoneNumber)
                .map(PhoneNumber::getNumber)
                .orElse(0);
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import java.util.Optional;

import static org.assertj.core.api.AssertionsForClassTypes.assertThat;

class PhoneNumberExtractorTest {

    @Test
    void return_0_when_user_is_null() {
        Integer phoneNumber = PhoneNumberExtractor.extract(null);

        assertThat(phoneNumber).isEqualTo(0);
    }

    @Test
    void return_0_when_address_is_null() {
        Integer phoneNumber = PhoneNumberExtractor.extract(User.builder().address(null).build());

        assertThat(phoneNumber).isEqualTo(0);
    }

    @Test
    void throws_NullPointerException_when_phone_number_is_null() {
        Optional<Address> address = Optional.of(Address.builder().phoneNumber(null).build());
        User user = User.builder().address(address).build();

        Assertions.assertThrows(NullPointerException.class, () -> PhoneNumberExtractor.extract(user));
    }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
import lombok.Builder;
import lombok.Getter;

import java.util.Optional;

@Builder
@Getter
public class User {
    private Optional<Address> address;
}

@Builder
@Getter
public class Address {
    private Optional<PhoneNumber> phoneNumber;
}

@Builder
@Getter
public class PhoneNumber {
    private Integer number;
}

9.5.2 分层架构

目的

通过分离关注点来降低系统的复杂度,同时满足单一职责、高内聚、低耦合、提高可复用性和降低维护成本

使用建议

  • 分层只知道直接的下层
  • 或者可以宽松一些:分层可以访问它之下的任何分层
    • Martin Fowler 的经验是在实际中使用这个方法会更好,因为它避免了在中间分层创建代码(或者完整的代理类)

10.1 不教条

软件的第一性原理是“控制软件复杂度”。

但凡能提高代码可读性、可扩展性和可维护性的方法,都是值得考虑的,并不一定要拘泥于某种特定的开发过程或者编程范式。

10.1.2 贫血还是充血

使用哪个,核心在于是否能有效的控制复杂度

10.4 结构化思维

5W2H 分析法

  • Why
  • Who
  • When
  • Where
  • What
  • How
  • How much

10.4.2 如何做晋升述职

提出问题 -> 定义问题 -> 分析问题 -> 解决问题 -> 最后展望未来

另一个思维 zoom in / zoom out

说事情时,先从宏观背景开始,让大家知道事情发生的背景,为什么这件事很重要?

然后讲到具体细节,怎么做成的?

解决了什么问题?

后端思考是什么?

最后,从细节回到整体,结果是什么?带来的客户价值是什么?你对未来的思考是什么?

11.3.4 团队特色

把攻克软件复杂度作为首要技术目标

12.2.2 CQRS

命令查询分离(Command Query Separation, CQS)

最早是 Betrand Meyer(Eiffel 语言之父,OCP 的提出者)提出的概念,其基本思想 在于任何一个对象的方法可以分为以下两类:

  • 命令(Command):不返回任何结果,但会改变对象的状态
  • 查询(Query):返回结果,但不会改变对象的状态,对系统没有副作用

命令查询职责分离模式(Command Query Responsibility Segregation, CQRS)

是对 CQS 模式的改进而成的一种简单架构模式。

该模式从业务上分离修改(增、删、改)和查询的行为,从而使逻辑更加清晰。

  • 该模式是读写分离的,有利于优化读写操作
  • 让代码更清晰简洁、更能体现出领域,易于维护
  • 是封装、低耦合、高内聚、单一责任原则的体现

待学习

第 3 章 函数

  • 3.7.2 优化缓存判断
  • 3.7.3 优雅降级
  • 3.8 组合函数模式(组合函数模式出自 Kent Beck 的《Smalltalk Best Practice Patterns》)
  • 3.10 函数编程
    • 减少冗余代码,让代码更简洁、可读性更好
    • “无副作用”,都是线程安全的不可变对象

第 7 章 DDD 的精髓

  • 领域实体
  • 聚合根
  • 领域服务
  • 领域事件
  • 四色建模法
  • InfoQ 运用四色建模法进行领域分析
  • Robert C. Martin 的《架构整洁之道》中作者提出:整洁的架构应该是“核心业务逻辑和技术细节相分离”的
comments powered by Disqus