Programadores seniores de grandes fábricas falam sobre código bom e código ruim

Para escrever um bom código, primeiro você precisa melhorar seu gosto.

Muitos engenheiros de software não conseguem escrever um bom código e não conseguem ver o problema ao revisar o código de outras pessoas, porque eles não entendem os bons padrões de código.

Ainda há muitos engenheiros de software hoje que pensam que o código só precisa ser executado corretamente. Este é um padrão de avaliação muito baixo, e muitos aspectos importantes são negligenciados.

Características de um bom código

Um bom código tem as seguintes características.

  1. Robusto (Sólido e Robusto)

Não apenas o código precisa ser executado corretamente, mas também precisamos considerar o tratamento de várias condições de erro, como exceções a várias chamadas de sistema e chamadas de função, exceções e erros de componentes relacionados ao sistema.

Para muitos programas de nível de produção, a lógica de tratamento de exceções e erros é responsável por uma grande proporção.

  1. Eficiente (Rápido)

A operação do programa deve utilizar o mínimo de recursos possível. Os recursos incluem não apenas CPUs, mas também armazenamento, E/S, etc.

Projetar programas eficientes aplicará o conhecimento de estruturas de dados e algoritmos, levando em consideração as restrições do tempo de execução do programa.

  1. Conciso (Manutenível e Simples)

A lógica do código deve ser tão simples e fácil de entender quanto possível, e o código deve ter boa manutenção. Para o mesmo objetivo, você pode usar métodos simples e claros para alcançar, não métodos complexos e obscuros.

"Caminho para a simplicidade", se problemas complexos podem ser realizados de maneira simples, esta é uma manifestação do nível de programação.

  1. curto

De certa forma, a complexidade e o custo de manutenção do código estão diretamente relacionados ao tamanho do código. Ao implementar a mesma função, tente manter o código o mais curto possível.

A brevidade é melhor do que a brevidade. Deve-se notar aqui que, para manter o código curto, algumas pessoas usam alguns métodos de descrição obscuros, o que reduz a legibilidade do código. Esta forma não é aconselhável.

  1. Testável

A correção do código deve ser garantida por meio de testes, principalmente em cenários ágeis, e é necessário contar com casos de teste que podem ser regredidos e executados automaticamente.

No projeto do código, devemos considerar como tornar o código testável e fácil de testar. Uma prática melhor é usar o método TDD (Test-Driven Development), para que ao escrever casos de teste, a testabilidade do código seja descoberta rapidamente.

  1. Compartilhar (reutilizável)

Um grande número de programas realmente usa estruturas ou lógica semelhantes. Devido à popularidade atual do código-fonte aberto, muitas funções não precisam ser desenvolvidas repetidamente e só podem ser referenciadas e usadas.

在一个组织内部,应鼓励共享和重用代码,这样可以有效降低代码研发的成本,并提升代码的质量。

实现代码的共享,不仅需要在意识方面提升,还需要具有相关的能力(如编写独立、高质量的代码库)及相关基础设施的支持(如代码搜索、代码引用机制)。

  1. 可移植(Portable)

某些程序需要在多种操作系统下运行,在这种情况下,代码的可移植性成为一种必需的能力。

要让代码具有可移植性,需要对所运行的各种操作系统底层有充分的理解和统一抽象。一般会使用一个适配层来屏蔽操作系统底层的差异。

一些编程语言也提供了多操作系统的可移植性,如很多基于Python语言、Java语言、Go语言编写的程序,都可以跨平台运行。

  1. 可观测(Observable) / 可监控(Monitorable)

面对目前大量存在的在线服务(Online Service)程序,需要具备对程序的运行状态进行细致而持续监控的能力。

这要求在程序设计时就提供相关的机制,包括程序状态的收集、保存和对外输出。

  1. 可运维(Operational)

可运维已经成为软件研发活动的重要组成部分,可运维重点关注成本、效率和稳定性三个方面。

程序的可运维性和程序的设计、编写紧密相关,如果在程序设计阶段就没有考虑可运维性,那么程序运行的运维目标则难以达成。

  1. 可扩展(Scalable and Extensible)

可扩展包含“容量可扩展”(Scalable)和“功能可扩展”(Extensible)两方面。

在互联网公司的系统设计中,“容量可扩展”是重要的设计目标之一。系统要尽量支持通过增加资源来实现容量的线性提高。

快速响应需求的变化,是互联网公司的另外一个重要挑战。可考虑使用插件式的程序设计方式,以容纳未来可能新增的功能,也可考虑使用类似Protocol Buffer 这样的工具,支持对协议新增字段。

坏代码的例子

关于好代码,上面介绍了一些特性,本节也给出坏代码(Bad Code)的几个例子。关于坏代码,本书没有做系统性总结,只是希望通过以下这些例子的展示让读者对坏代码有直观的感觉。

  1. 不好的函数名称(Bad Function Name)

如do(),这样的函数名称没有多少信息量;又如myFunc(),这样的函数名称,个人色彩过于强烈,也没有足够的信息量。

  1. 不好的变量名称(Bad Variable Name)

如a、b、c、i、j、k、temp,这样的变量名称在很多教科书中经常出现,很多人在上学期间写代码时也会经常这样用。如果作为局部变量,这样的名称有时是可以接受的;但如果作为作用域稍微大的变量,这样的名称就非常不可取了。

  1. 没有注释(No Comments)

有写注释习惯的软件工程师很少,很多软件工程师认为写注释是浪费时间,是“额外”的工作。但是没有注释的代码,阅读的成本会比较高。

  1. 函数不是单一目的(The Function has No Single Purpose)

如LoadFromFileAndCalculate()。这个例子是我编造的,但现实中这样的函数其实不少。很多函数在首次写出来的时候,就很难表述清楚其用途;还有一些函数随着功能的扩展,变得越来越庞杂,也就慢慢地说不清它的目的了。

这方面的问题可能很多人都没有充分地认识到——非单一目的的函数难以维护,也难以复用。

  1. 不好的排版(Bad Layout)

不少人认为,程序可以正常执行就行了,所以一些软件工程师不重视对代码的排版,认为这仅仅是一种“形式”。

没有排好版的程序,在阅读效率方面会带来严重问题。这里举一个极端的例子:对于C语言来说,“;”可作为语句的分割符,而“缩进”和“换行”对于编译器来说是无用的,所以完全可以把一段C语言程序都“压缩”在一行内。这样的程序是可以运行的,但是对人来说,可读性非常差。这样的程序肯定是我们非常不希望看到的。

  1. 无法测试(None Testable)

程序的正确性要依赖测试来保证(虽然测试并不能保证程序完全无错)。无法或不好为之编写测试用例的程序,是很难有质量保证的。

好代码从哪里来

上一节说明了好代码的特性,本节来分析好代码是如何产出的。

▊ 好代码不止于编码

好代码从哪里来?

对于这个问题,很多读者肯定会说:“好代码肯定是写出来的呀。”

我曾做过多次调研,发现很多软件工程师日常所读的书确实是和“写代码”紧密相关的。

但是,这里要告诉读者的是,代码不只是“写”出来的。在很多年前,我所读的软件工程方面的教科书就告诉我,编码的时间一般只占一个项目所花时间的 10%。我曾说过一句比较有趣的话:

“如果一个从业者告诉你,他的大部分时间都在写代码,那么他大概率不是一个高级软件工程师。”

那么,软件工程师的时间都花到哪里去了呢?软件工程师的时间应该花在哪里呢?

好的代码是多个工作环节的综合结果。

(1)在编码前,需要做好需求分析和系统设计。而这两项工作是经常被大量软件工程师忽略或轻视的环节。

(2)在编码时,需要编写代码和编写单元测试。对于“编写代码”,读者都了解;而对于“编写单元测试”,有些软件工程师就不认同了,甚至还有人误以为单元测试是由测试工程师来编写的。

(3)在编码后,要做集成测试、上线,以及持续运营/迭代改进。这几件事情都是要花费不少精力的,比如上线,不仅仅要做程序部署,而且要考虑程序是如何被监控的。有时,为了一段程序的上线,设计和实施监控的方案要花费好几天才能完成。

因此,一个好的系统或产品是以上这些环节持续循环执行的结果。

▊ 需求分析和系统设计

  1. 几种常见的错误现象

相对于编码工作,需求分析和系统设计是两个经常被忽视的环节。在现实工作中,我们经常会看到以下这些现象。

(1)很多人错误地认为,写代码才是最重要的事情。不少软件工程师如果一天没有写出几行代码,就会认为工作没有进展;很多管理者也会以代码的产出量作为衡量工作结果的主要标准,催促软件工程师尽早开始写代码。

(2)有太多的从业者,在没有搞清楚项目目标之前就已经开始编码了。在很多时候,项目目标都是通过并不准确的口头沟通来确定的。例如:

“需要做什么?”

“就按照×××网站的做一个吧。”

(3)有太多的从业者,在代码编写基本完成后,才发现设计思路是有问题的。他们在很多项目上花费很少(甚至没有花费)时间进行系统设计,对于在设计中所隐藏的问题并没有仔细思考和求证。基于这样的设计投入和设计质量,项目出现设计失误也是很难避免的。而面对一个已经完成了基本编码的项目,如果要“动大手术”来修改它,相信每个有过类似经历的人都一定深知那种感受——越改越乱,越改越着急。

以上这几种情况,很多读者是不是都有过类似经历?

  1. 研发前期多投入,收益更大

关于软件研发,首先我们需要建立一个非常重要的观念。

在研发前期(需求分析和系统设计)多投入资源,相对于把资源都投入在研发后期(编码、测试等),其收益更大。

这是为什么呢?

要回答这个问题,需要从软件研发全生命周期的角度来考量软件研发的成本。除编码外,软件测试、上线、调试等都需要很高成本。如果我们把需求搞错了,那么与错误需求有关的设计、编码、测试、上线等成本就都浪费了;如果我们把设计搞错了,那么与错误设计相关的编码、测试、上线的成本也就浪费了。

如果仔细考量那些低效的项目,会发现有非常多的类似于上面提到的“浪费”的地方。软件工程师似乎都很忙,但是在错误方向上所做的所有努力并不会产生任何价值,而大部分的加班实际上是在做错误的事情,或者是为了补救错误而努力。在这种情况下,将更多的资源和注意力向研发前期倾斜会立刻收到良好的效果。

  1. 修改代码和修改文档,哪个成本更高

很多软件工程师不愿意做需求分析和系统设计,是因为对“写文档”有着根深蒂固的偏见。这里问大家一个问题,如果大家对这个问题能给出正确的回答,那么在“写文档”的意识方面,一定会有很大的转变。

任何人都不是神仙,无法一次就把所有事情做对。对于一段程序来说,它一定要经过一定周期的修改和迭代。这时有两种选择:

选择一:修改文档。在设计文档时完成迭代调整,待没有大问题后再开始编码。

选择二:修改代码。只有粗略的设计文档,或者没有设计文档,直接开始编码,所有的迭代调整都在代码上完成。

请大家判断,修改代码和修改文档,哪个成本更高?

在之前的一些分享交流会上,对于这个问题,有人会说,修改文档的成本更高。因为在修改文档后还要修改代码,多了一道手续。而直接修改代码,只需要做一次,这样更直接。

这个回答说明了回答者没有充分理解“先写文档,后写代码”的设计方法。如果没有充分重视设计文档的工作,在输出的设计文档质量不高的情况下就开始编码,确实会出现以上提到的问题。但是,如果在设计文档阶段就已经做了充分考虑,会减少对代码的迭代和反复。

对于同样的设计修改,“修改代码”的成本远高于“修改文档”。这是因为,在设计文档中只会涉及主要的逻辑,那些细小的、显而易见的逻辑不会在设计文档中出现。在修改设计文档时,也只会影响到这些主要逻辑。而如果在代码中做修改,不仅会涉及这些主要逻辑,而且会涉及那些在文档中不会出现的细小逻辑。对于一段程序来说,任何一个逻辑出现问题,程序都是无法正常运行的。

  1. 需求分析和系统设计之间的差别

很多读者无法清楚地区分“需求分析”和“系统设计”之间的差别,于是会发现,在写出的文档中,有些需求分析文档里出现了系统设计的内容,而有些系统设计文档里又混杂了需求分析的内容。

我们用几句话可以非常明确地给出二者的差异。

(1)需求分析:定义系统/软件的黑盒的行为,它是从外部(External)看到的,在说明“是什么”(What)。

(2)系统设计:设计系统/软件的白盒的机制,它是从内部(Internal)看到的,要说明“怎么做”(How)和“为什么”(Why)。

比如,对一辆汽车来说,首先使用者从外部可以看到车厢、车轮,坐在车里可以看到方向盘、刹车踏板、油门踏板等;操作方向盘可以改变汽车的行驶方向,脚踩刹车踏板、油门踏板可用于减速和加速。以上这些是对汽车的“需求分析”。

然后,我们想象汽车外壳和内部变成了透明的,可以看到汽车内部的发动机、变速箱、传动杆、与刹车相关的内部装置等。而这些对驾驶者来说是不可见的,它们是对汽车的“系统设计”。

以上就是本次分享的所有内容,想要了解更多 python 知识欢迎前往公众号:Python 编程学习圈,每日干货分享

Acho que você gosta

Origin juejin.im/post/7105596452659232798
Recomendado
Clasificación