go 设计哲学

275 阅读6分钟

前言

任何事情在开始做之前,都会定下准则。后续的工作,也都是围绕这些准则进行。在编程语言和软件设计中,我们一般会称其为设计哲学。

我们在进行系统设计时,需要围绕编程语言的设计哲学,去设计方案。或者因其设计哲学,而选择其作为我们的技术栈。所以在学习编程语言中,最重要的是掌握编程语言的设计哲学,而不是语法。

最近在重读go语言精进之路,下文主要介绍从中获取的go语言设计哲学。go的设计哲学可以分为四类,主要如下:

  • 追求简单,少即是多
  • 偏好组合,正交耦合
  • 原生并发,轻量高效
  • 面向工程,自带电池

追求简单,少即是多

go语言的简单,写过其他语言的都会深有体会,相比其他语言,其语法特性大大减少。这主要是因为在设计之初,设计者拒绝走语言特性融合的道路,并不打算设计出一项大而全的语言,而是设计一门“够用”的语言。于是设计者对特性做“减法”,选择了“简单”, 比如对比java,没有抽象类。

设计者推崇“最小方式“思维,即一件事仅有一种方式或者尽可能少的实现方式去完成,这大大减少了开发者在选择路径抉择以及理解其他人的设计方案的心智负担;

  • 简单,常规的语法;go基础语法一般一天就能学完,作为对比,java的对象知识点可能都需要一天。
  • 内置垃圾回收: 不需要内存管理,解放心智负担。
  • 接口仅仅是方法集合: 不需要显式指定实现,大大降低了代码的变更难度。
  • 方法仅按照名称匹配:提升代码
  • 显式依赖,无循环依赖:提升代码清晰度,天然分层。
  • 内置并发支持:大大降低并发代码的编写难度, 一个go关键字,并发即完成。
  • 无构造函数:无需维护一些复杂的构造函数,降低维护难度

go追求的简单: 语法简单,语法特性少,设计围绕”够用“原则进行设计,降低程序员编码和维护的心智负担

偏好组合,正交耦合

也许是考虑了SOLID原值,go语言设计之初,提供了正交的语法元素,鼓励用户组合

  • go语言无类型体系,类型之间是相互独立的,没有子类型的概念。而一般的面向对象语言,均存在抽象类,子类,继承等众多概念。
  • 每个类型都可以有自己的方法集合,类型与方法之间是正交独立的。方法可以依赖类型独立存在,而不需要依赖类型。其他OO语言中,方法一般需要和类型绑定在一起。
  • 接口与其实现之间是隐式关联,“鸭子类型”;
    • 代码灵活度高,不需要显式申明实现
    • 减少代码依赖,开发者不需要关注对象的具体类型,对象只需要具体接口所需要的方法即可。
    • 方便单元测试
    • 天然多态。不同类型只要实现了相同的方法,就可以通过接口进行互换。
    • 方便进行单元测试。
  • 包之间是相互独立的,没有子包的概念;
    • 简化包管理(将简单贯彻到底)
    • 提高了代码的可读性,代码更容易理解
    • 鼓励进行模块化设计
  • 组合可以分为垂直组合和水平组合
    • 垂直组合:通过类型嵌入,可以让一个新类型快速复用其他类型已经具有的能力,实现功能上的垂直扩展
    • 水平组合:通过interface将各个部分组合在一起的方式,成为水平组合; interface是go中真正的魔法,它只是一个方法集合,与实现者之间的关系是隐式的,让程序之间的耦合降到最低,同时是程序连接各个部分的纽带,隐式的interface会不经意间满足依赖抽象,里式替换,接口隔离等设计原则。

组合优于继承,多用组合少用继承 ,go从语言特性层面天然支持

原生并发,轻量高效

go语言设计者敏锐的把握了cpu向多核方向发展的趋势,果断将面向多核,原生内置并发支持作为新语言设计的原则之一。其主特点如下

  • 采用协程并发模型,在面对多核硬件时更具扩展性。使用协层模型,大大降低了线程使用的资源占用,多线程的使用,不再具有资源负担。
  • 提供支持并发的语法元素和机制,使用简单,高效。执行一个线程,一个go关键字即可,且为线程提供了简单易用的同步,控制机制。如channel, waitgroup。

go的并发语法,大大降低了开发者使用多线程的门槛,方便开发者提升性能服务

面向工程,”自带电池“

软件工程指引着go语言的设计,go语言设计者将所有工程问题浓缩为一个词”scale"; 一般指:

  • 生产规模
  • 开发规模

go主要从三个方面来解决此问题:

  • 语言:简化语法,简单意味着可读性好,容易理解,容易上手,容易修复错误,节省开发时间,提升开发者间的沟通;类似还有去除包的循环依赖;不支持默认参数;内置垃圾回收;内置并发支持;增加别名,支持大规模重构;
  • 标准库:go被称为”自带电池“含义是,由于诞生时间较晚,且目标较为明确,go在标准库中提供了各类高质量且性能优异的功能包;减轻开发者对第三方包或者库的依赖;比如http库,测试库。
  • 工具链:go提供了十分全面的官方工具链。如 go build; go fmt; go doc; go test; go vet; go too pprof 等,这些工具涵盖了编译,编辑,依赖获取,调试,测试,文档,性能剖析等; 如使用pprof方便开发者进行系统调优, go fmt统一代码风格,大大降低代码的维护难度。

官方具备丰富的工具链,开发者可以专注于业务开发,而无需太多考虑业务之外第三方库选择问题。

最后

学习新语言,要去了解并理解新语言的设计哲学,切勿拿已经擅长的语言设计哲学或编码范式来指导新语言的开发与设计,否则将难以发挥出新语言的特性,最终难以掌握新语言的精髓。

参考:go语言精进之路