勿在浮沙聚高塔

Posted by YueLng Chen on 2017-11-30

1.摘要

今天看了新浪新兵训练营的一些资料,整理下关于程序员最基础的知识————关于编码
主要内容包括,什么是烂代码,什么是好代码,好代码需要注意什么,如何做出优雅的设计,如何规划合理的架构
编码主要是给人看的,其次才是给机器看的。
第一个保证用户逻辑是对的,第二个保证这算法写法性能最好的,第三保证相关成本是最低的包括内存分配成本垃圾回收成本

2.关于烂代码

写出烂代码很容易,入行时很容易被鼓吹要把主要精力放在ABCD(需求文档/功能设计/架构设计/理解原理)上,写代码只是实现想法的工具。在这样的指导思想下,也随着语言的特性,层层封装,不需要了解技术细节,只要逐行翻译出来就可以了,这往往就是写出烂代码的根本原因。
常见的烂代码的原因包括

  • 意义不明(写出没有必要的代码)
  • 不说人话(写出别人看不懂的代码,又缺乏注释)
  • 不恰当的组织(写过了一些代码,但是不会分离逻辑,经常说“分离出逻辑就会增加类”)
  • 考虑不周和缺乏抽象(码代码最重要的技能之一就是对代码的抽象能力,对情况的考虑不全也会造成不断修改代码)
  • 明知道写着烂代码,但是想着以后重构来解决。重构不是万能药,
    写好代码很难

  • 理解要开发的功能需求

  • 了解程序的运行原理
  • 做出合理的抽象
  • 组织复杂的逻辑
  • 对自己开发效率的正确估算
  • 持续不断的练习

3.什么是好代码

Bjarne Stroustrup,C++之父:

  • 逻辑应该是清晰的,bug难以隐藏;
  • 依赖最少,易于维护;
  • 错误处理完全根据一个明确的策略;
  • 性能接近最佳化,避免代码混乱和无原则的优化;
  • 整洁的代码只做一件事。

Grady Booch,《面向对象分析与设计》作者:

  • 整洁的代码是简单、直接的;
  • 整洁的代码,读起来像是一篇写得很好的散文;
  • 整洁的代码永远不会掩盖设计者的意图,而是具有少量的抽象和清晰的控制行。

Michael Feathers,《修改代码的艺术》作者:

  • 整洁的代码看起来总是像很在乎代码质量的人写的;
  • 没有明显的需要改善的地方;
  • 代码的作者似乎考虑到了所有的事情。

代码质量的评价标准某种意义上有点类似于文学作品,比如对小说的质量的评价主要来自于它的读者,由个体主观评价形成一个相对客观的评价。并不是依靠字数,或者作者使用了哪些修辞手法之类的看似完全客观但实际没有什么意义的评价手段。
可读的代码

  • 逐字翻译,将你的代码思路给小黄鸭或者给没有看过你代码的人表述一遍
  • 遵循约定,包括代码和文档如何组织,注释如何编写,编码风格。可以参考google code style,这里有中文版
  • 文档与注释,文档主要有三类

1、对于项目的介绍,包括项目功能、作者、目录结构等,读者应该能3分钟内大致理解这个工程是做什么的。
2、针对新人的QuickStart,读者按照文档说明应该能在1小时内完成代码构建和简单使用。
3、针对使用者的详细说明文档,比如接口定义、参数含义、设计等,读者能通过文档了解这些功能(或接口)的使用方法。

  • 可发布的代码,对于线上出现的问题能够快速定位问题,并解决

3.好代码应该注意哪些

  • 异常处理,单元测试的覆盖率,一定要尽可能地模拟线上环境地测试
  • 处理并发,具有对共享资源调用的敏感度。
  • 日志,评判日志的标准
  • 编码规范,参考知名开源项目的代码风格,golib
  • 日志是否足够,所有异常、外部调用都需要有日志,而一条调用链路上的入口、出口和路径关键点上也需要有日志。
  • 日志的表达是否清晰,包括是否能读懂,风格是否统一等。这个的评价标准跟代码的可读性一样,不重复了。
  • 日志是否包含了足够的信息,这里包括了调用的上下文、外部的返回值,用于查询的关键字等,便于分析信息。
  • 避免重复
  • 模块划分
  • 简介与抽象

4.如何做出优雅的设计

参考设计模式

  • 创建型模 式主要用于创建对象 式主要用于创建对象 。 
  • 结构型模式主要用于处理类或对象的组合。 
  • 行为型模式主要用于描述对类或对象怎样交互和怎样分配职责。
    编写单元测试
    几个比较常见的单元测试的几个典型场景:
  1. 开发前写单元测试,通过测试描述需求,由测试驱动开发。
  2. 在开发过程中及时得到反馈,提前发现问题。
  3. 应用于自动化构建或持续集成流程,对每次代码修改做回归测试。
  4. 作为重构的基础,验证重构是否可靠。
    单元测试测的三分是代码,七分是设计,能写出单元测试的代码基本上可以说明这段代码的设计是比较合理的。能写出和写不出单元测试之间体现了编程能力上的巨大的鸿沟,无论是什么样的程序员,坚持编写一段时间的单元测试之后,都会明显感受到代码设计能力的巨大提升。

5.如何规划合理的架构

常见的架构模式

5.1分层架构


在现实的场景中,层数不是定值,需要根据业务的复杂度而定。在分层模型中一般来说不能跨层、同层、或反向调用,否则会让层次模型由单一的树形结构变为网状结构,失去分层的意义。
如果要严格按照分层模型逐级调用,会产生许多无用的空层,作用只是传递请求,因此可以对每个层次规定“开放”或“关闭”属性,对于“开放”的层次,上层可以越过这层,直接访问下层,确保团队成员对分层架构的“开放”规则有相应的了解。

5.2事件驱动架构

事件驱动架构能比较好的解耦请求方和处理方,经常被用在写入请求量变化较大,或者是请求方不关心处理逻辑的场景中,它有两种主要的实现方式:
Mediator
在mediator方式中,存在一个中介者角色,它接收写入方的请求,并把事件分配到对应的处理方(图中的channel),每个处理方只需要关心自己的channel,而不需要与写入方直接通信。

Broker
在broker方式中不存在中介者的角色,取而代之的是消息流在轻量的processor中流转,形成一个消息处理的链路,如图:

前一段时间开始推广的storm流式处理属于这种模式,对于较长的处理流程,用broker方式可以避免实现Mediator的复杂性,相对的,管理整个流程变得复杂了。

5.3微内核架构(Microkernel)

微内核架构相对于普通架构最主要的区别是多了“内核”的概念,在编写程序时把基础功能和扩展功能分离:内核中不再实现具体功能,而是定义“扩展点”,增加功能时不再修改主逻辑,而是通过“扩展点”挂接到内核中,如图:

之前介绍的motan RPC框架应用了这种设计,这让motan可以通过不同的插件支持更多的功能,比如增加传输协议、定义新的服务发现规则等。

5.3微服务架构

近年来微服务架构的概念一直比较火,它可以解决服务逐渐增长之后造成的难以测试及部署、资源浪费等问题,但也带来了服务调度和服务发现层面的复杂度,如图:

微服务隔离了各服务之间的耦合,能够有效提升开发效率

参考