软件复杂性解决之道
目录
1.1. 关于代码重构降低圈复杂度三个目标:提高代码质量、提升开发效率、提升性能,
9.1. 项目启动时考虑任务划分,公共代码、接口与聚合根的任务划分
9.2. API工程是公共工程,为代码复用,每个开发可以拉分支
9.3. 服务工程主要是接口,无复杂逻辑,除主分支外只要拉一个临时分支即可
9.6. DB操作,ES操作分开,复杂的场景使用DB和ES组合,不应在一个函数中嵌入复杂的DB操作和ES操作同时有DB和ES操作的函数实现,复杂度应<=10;
9.7. 使用面向对象和面向接口的编程方式,接口分面向实现和面向使用的接口两种。
9.8. 公共代码的冲突影响效率,需要从管理和技术两个维护解决,公共是为了复用; 维护公共代码有一定成本,但可以减少代码重复,减少维护成本、提高代码质量。
软件复杂性解决之道
--面向对象和设计模式
二〇二四年九月五日星期四
1. 我们的目标
1.1. 关于代码重构降低圈复杂度三个目标:提高代码质量、提升开发效率、提升性能,
1.2. 提升性能一定是最后才能达成。
1.3. 因为需求的复杂度,代码复杂度以业务、订单为甚。
2. 软件复杂性解决之道
软件复杂性是软件开发中一个不可避免的挑战,它通常随着软件功能的增加和系统规模的扩大而增加。以下是一些解决软件复杂性的策略:
1.4. 简化需求:
在项目开始时,明确和简化需求,避免不必要的功能,专注于核心价值。
1.5. 模块化:
将系统分解成独立的、可管理的模块,每个模块负责特定的功能,减少模块间的依赖。
1.6. 设计模式:
采用设计模式来解决常见的设计问题,这些模式是经过验证的解决方案,可以提高代码的可读性和可维护性。
1.7. 代码重构:
定期重构代码以提高其可读性和可维护性,去除重复代码,优化结构。
1.8. 自动化测试:
实施自动化测试来确保代码的稳定性和可靠性,减少手动测试的复杂性。
1.9. 持续集成/持续部署(CI/CD):
通过自动化的构建和部署流程来减少人为错误,提高软件交付的速度和质量。
1.10. 代码审查:
实行代码审查流程,确保代码质量,及早发现和修复问题。
1.11. 文档化:
编写清晰的文档和代码注释,帮助团队成员理解系统的设计和实现。
1.12. 限制功能蔓延:
控制新功能的添加,确保它们真正为用户带来价值,避免功能过度膨胀。
1.13. 选择合适的工具和技术:
使用适合项目需求的工具和技术,可以提高开发效率和软件质量。
1.14. 团队协作:
加强团队沟通和协作,确保团队成员对软件的各个方面有共同的理解。
1.15. 性能优化:
优化软件性能,确保它在资源受限的环境中也能高效运行。
1.16. 领域驱动设计(DDD):
采用领域驱动设计来更好地理解和建模业务领域,从而提高软件的可维护性和可扩展性。
1.17. 微服务架构:
如果适用,采用微服务架构将大型应用分解为一组小型、独立的服务,每个服务负责一部分业务功能。
1.18. 监控和日志:
实施有效的监控和日志记录,以便及时发现和解决问题。
通过这些策略,可以有效地管理和降低软件复杂性,提高软件的质量和开发效率。
3. 代码复杂性度量:
圈复杂度(Cyclomatic complexity)是一种衡量代码复杂度的标准,由托马斯·J·麦凯布(Thomas J. McCabe, Sr.)于1976年提出,用来表示程序的复杂度,符号为v(G)。它用来衡量一个模块判定结构的复杂程度,数量上表现为独立路径条数,也可表示为覆盖软件所有的可能情况最少使用的测试用例数。圈复杂度越高说明程序的判断逻辑越复杂,可能致使程序质量低且难于测试和维护。程序的缺陷和高圈复杂度有着很大关系,圈复杂度最高的模块,其缺陷个数也可能最多。McCabe将圈复杂度限制为10。圈复杂度可应用在程序的子程序、模块、方法或类中。
对复杂度基本可以分为以下几个级别:
· 1 - 10 程序简单,风险小
· 11 - 20 更复杂,中等风险
· 21 - 50 复杂、高风险
· 50 不可测试的代码,非常高的风险
go install github.com/fzipp/gocyclo/cmd/gocyclo@latest
gocyclo -top 5 .\core
289 handler (*Handler).OrderEdit commerce-order-srv\handler\order.go:6708:1
152 handler (*Handler).orderEditApprove commerce-order-srv\handler\order.go:8536:1
95 handler (*Handler).fulfillmentItemConfirm commerce-order-srv\handler\fulfillment_item.go:88:1
93 handler (*Handler).createFulfillmentItem commerce-order-srv\handler\subscribe.go:785:1
91 handler (*Handler).lineItemUpdate commerce-order-srv\handler\line_item.go:2210:1
90 handler (*Handler).platformBuyPayment commerce-order-srv\handler\order_payment_oper.go:171:1
84 handler (*Handler).orderPayment commerce-order-srv\handler\order.go:3181:1
70 handler (*Handler).createOrder commerce-order-srv\handler\order.go:150:1
本文重点在面向对象、设计模式; 领域驱动形成业务的设计模式:
4. 面向对象编程概念:代码界的领域驱动
面向对象编程(Object-Oriented Programming,简称 OOP)是一种编程范式,它使用“对象”来设计应用程序和程序结构。在这种范式中,对象可以包含数据(通常称为属性或字段)和代码(通常称为方法或函数)。面向对象编程的核心概念包括:
对象是现实世界中事物的抽象,它包含状态(数据)和行为(代码)。例如,一个“汽车”对象可能包含属性如颜色、品牌和速度,以及方法如启动、加速和刹车。
类是对象的蓝图或模板,定义了一组属性和方法。通过类可以创建多个具有相同属性和方法的对象实例。
封装是将数据(属性)和操作这些数据的方法(行为)捆绑在一起的过程,并对外部隐藏内部细节。这提高了安全性和简化了复杂性。
继承是一种机制,允许一个类(子类或派生类)继承另一个类(父类或基类)的属性和方法。这支持代码重用和建立层次结构。
多态是指对象可以采用多种形态的能力。在面向对象编程中,多态通常指的是方法重载(同一个类中方法名相同但参数不同)和方法覆盖(子类重写父类的方法)。
抽象是简化复杂性的过程,它涉及隐藏实现细节并只展示必要的信息。在面向对象编程中,可以通过接口或抽象类来实现。
通过继承和多态,可以减少重复代码,提高开发效率。
通过封装,可以将复杂的系统分解为更小、更易于管理的部分。
面向对象的设计使得修改和扩展现有代码更加容易。
面向对象的代码通常更接近自然语言,因此更易于理解和维护。
面向对象编程被广泛应用于各种编程语言中,如Java、C++、Python、C#等,每种语言都有其特定的实现方式和特性。
5. 面向对象如何在go落地
Go 语言是一种静态类型的编译型语言,它并不支持传统的面向对象编程(OOP)中的类和继承概念。但是,Go 语言提供了一种结构体(struct)和接口(interface)的方式来实现类似面向对象编程的特性。以下是在 Go 语言中实现面向对象编程的一些关键概念:
在 Go 语言中,结构体类似于其他语言中的类。它是一个可以包含多个不同类型字段的复合数据类型。
type Animal struct {
Name string
Age int
}
你可以为结构体定义方法,这类似于其他语言中类的方法。方法就是接收者为特定类型的函数。
func (a Animal) Speak() string {
return "Some sound"
}
Go 语言中的接口是一种类型,它定义了一组方法。任何实现了接口中所有方法的类型都实现了该接口。
type Speakable interface {
Speak() string
}
Go 语言鼓励使用组合而不是继承。你可以通过将一个类型的实例作为另一个类型的字段来实现代码的复用。
type Dog struct {
Animal
}
嵌入是 Go 语言特有的一种方式,它允许一个结构体嵌入另一个结构体,从而继承其方法。
type Dog struct {
Animal
}
func (d Dog) Speak() string {
return "Woof!"
}
在需要的时候,你可以使用类型断言来检查一个接口变量的实际类型,并进行相应的操作。
s := someInterface{}
if dog, ok := s.(Dog); ok {
fmt.Println(dog.Speak())
}
任何类型只要实现了接口中定义的所有方法,就自动实现了该接口,无需显式声明。
func (d Dog) Speak() string {
return "Woof!"
}
// Dog 实现了 Speakable 接口
通过这些机制,你可以在 Go 语言中实现面向对象的设计模式和原则,尽管它的实现方式与传统的面向对象语言有所不同。在 Go 中,更强调的是简洁和并发编程,而不是复杂的类继承体系。
6. GO面向接口编程场景
在Go语言中,面向接口编程是一种强大的设计模式,它能够帮助我们构建灵活、可扩展且易于维护的软件系统。以下是一些面向接口编程的使用场景:
通过定义接口,可以将实现细节与高层业务逻辑分离,使得代码更加模块化。例如,可以为数据库操作定义一个 Datastore 接口,不同的数据库实现(如MySQL、MongoDB)都可以实现这个接口,而在高层逻辑中只需要使用 Datastore 接口,这样可以轻松切换不同的数据库实现而不需要修改业务逻辑代码。
接口允许不同的类型对象对同一消息做出响应,这是多态的核心。例如,可以定义一个 Logger 接口,然后实现多个具体的日志记录器(如 ConsoleLogger 、 FileLogger ),在程序中可以根据需要选择合适的日志记录器。
- 成交数 --
- 成交额 --
- 应答率