读书笔记 | 程序员修炼之道

Author

华丽

PublishDate

2022-03-05

《程序员修炼之道》

摘抄

  • 要提供各种选择,而不是找借口。不要说事情做不到;要说明能够做什么来挽回局面。

  • 不要留「破窗户」(低劣的设计、错误决策、或者糟糕的代码)不修。发现一个就修一个。采取某种行动防止进一步的损坏,并说明情势处在你的控制之下。

  • 要持续不断地观察周围发生的事情,而不只是你自己在做的事情。

  • 作为底线,你需要知道你目前所用的特定技术的各种特性。你掌握的技术越多,你就越能更好地进行调整,赶上变化。

  • 作为开发者,我们必须在许多层面上进行交流。我们把许多小时花在开会、倾听和交流上。我们与最终用户一起工作,设法了解他们的需要。我们编写代码,与机器交流我们的意图;把我们的想法变成文档,留给以后的开发者。我们撰写提案和备忘录,用以申请资源并证明其正当性、报告我们的状态、以及提出各种新方法。我们每天在团队中工作,宣扬我们的主意、修正现有的做法、并提出新的做法。我们的时间有很大一部分都花在交流上,所以我们需要把它做好。

  • 了解听众

    你想让他们学到什么?

    他们对你讲的什么感兴趣?

    他们有多富有经验?

    他们想要多少细节?

    你想要让谁拥有这些信息?

    你如何促使他们听你说话?

  • 系统中的每一项知识都必须具有单一、无歧义、权威的表示。

    DRY - Don’t Repeat Yourself

  • 你可以因为性能原因而选择违反 DRY 原则。这经常会发生在你需要缓存数据,以避免重复昂贵的操作时。其诀窍是使影响局部化。对 DRY 原则的违反没有暴露给外界。

  • 构建单元测试本身是对正交性的一项有趣测试。要构建和链接某个单元测试,都需要什么?只是为了编译或链接某个测试,你是否就必须把系统其余的很大一部分拽进来?如果是这样,你已经发现了一个没有很好解除与系统其余部分耦合的模块。

  • 原型制作生成用过就扔的代码。曳光代码虽然简约,但却是完整的,并且构成了最终系统的骨架的一部分。

  • 下面是一些你可以在架构原型中寻求解答的具体问题:

    主要组件的责任是否得到了良好定义?是否适当?

    主要组件间的写作是否得到了良好定义?

    耦合是否得以最小化?

    你能否确定重复的潜在来源?

    接口定义和各项约束是否可接受?

    每个模块在执行过程中是否能访问到其所需的数据?是否能在需要时进行访问?

  • 对任何数量的估算:要选择能反映你想要传达的精确度的单位。

  • 在调试时小心「近视」。要总是设法找出问题的根源,而不只是问题的特定表现。

  • 调试从何处开始

    你也许需要与报告 bug 的用户面谈,以搜集比最初给你的数据更多的数据。

    人工合成的测试不能足够地演练应用。你必须既强硬地测试边界条件,又测试现实中的最终用户的使用模式。你需要系统地进行这样的测试。

  • 找到问题的原因的一种非常简单、却又特别有用的技术是向别人解释它。你只是一步步解释代码要做什么,常常就能让问题从屏幕上跳出来,宣布自己的存在。

  • 当你遇到让人吃惊的 bug 时,除了只是修正它之外,你还需要确定先前为什么没有找出这个故障。考虑你是否需要改进单元测试或其它测试,以让它们有能力找出这个故障。

  • 当你的代码发现,某件被认为不可能发生的事情已经发生时,你的程序就不再有存活能力。从此时开始,它所做的任何事情都会变得可疑,所以要尽快终止它。死程序带来的危害通常比有疾患的程序要小得多。

  • 不要用断言代替真正的错误处理。断言检查的是绝不应该发生的事情。

  • 得墨忒耳定律

    得墨忒耳定律( Law of Demeter,缩写 LoD )亦被称作 “最少知识原则(Principle of Least Knowledge)”,是一种软件开发的设计指导原则,特别是面向对象的程序设计。得墨忒耳定律是松耦合的一种具体案例。

    1. 每个单元对于其他的单元只能拥有有限的知识:只是与当前单元紧密联系的单元;
    2. 每个单元只能和它的朋友交谈:不能和陌生单元交谈;
    3. 只和自己直接的朋友交谈。
  • 每个模块都有其自身的责任;事实上,模块(或类)的一个好定义就是,它具有单一的、定义良好的责任。

  • 黑板系统让我们完全解除了我们的对象之间的耦合,并提供了一个「论坛」,知识消费者和生产者可以在那里匿名、异步地交换数据。

各种算法的运行时间

  • 无论代码具有下面的哪些特征,你都应该考虑重构代码:

    • 重复。你发现了对 DRY 原则的违法。

    • 非正交的设计。你发现有些代码或设计可以变得更加正交。

    • 过时的知识。事情变了,需求转移了,你对问题的了解加深了。代码需要跟上这些变化。

    • 性能。为改善性能,你须要把功能从系统的一个区域移到另一个区域。

  • 我们想要编写测试用例,确保给定的单元遵守其合约。这将告诉我们两件事:代码是否符合合约,以及合约的含义是否与我们所认为的一样。我们想要通过广泛的测试用例与边界条件,测试模块是否实现了它允诺的功能。

  • 使需求成为一般陈述。政策可以成为应用中的元数据。

    只有员工的上级才可以查看员工的档案。 –> 只有指定的人员才能查看员工的档案。

  • 好的需求文档会保持抽象。在涉及需求的地方,最简单的、能够准确地反映商业需要的陈述是最好的。

  • 管理需求增长的关键是向投资人指出每项新特性对项目进度的影响。

  • 如果你认为某个特定问题是「不可能解决的」,可以问问自己一下问题:

    • 有更容易的方法吗?

    • 你是在设法解决真正的问题,还是被外围的技术问题转移了注意力?

    • 这件事情为什么是一个问题?

    • 是什么使它如此难以解决?

    • 它必须以这种方式完成吗?

    • 它真的必须完成吗?

  • 项目的分析、设计、编码、测试,不会孤立地发生。它们是看待同一个问题的不同方式,人为地分隔它们会带来很多麻烦。

  • 给用户的要比他们期望的多一点。给系统增加某种面向用户的特性所需的一点额外努力将一次又一次在商誉上带来回报。

笔记

整本书是比较偏向软件工程方面的,实际代码的编写方面涉及的比较少,所以读起来其实挺快的,特别是结合自己实际写代码的实践经历,能够和作者产生很多共鸣,得到很多的启发。

印象最深刻的三点是 DRY 原则、正交设计以及认清客户的真实需求。

编写组件

看书的同时我还看完了 b 站上 跟尤雨溪一起解读 Vue3 源码 的视频,对 vue 的认识也更深了一些。正好业务上也有一些新的功能要写,我结合正交设计原则对组件进行了较好的封装。

<script lang="ts">
import { defineComponent, ref } from "vue";

export default defineComponent({
  name: "Test",
  props: {
    msg: String,
  },
  setup() {
    const showDialog = ref(false);

    function handleClick() {
      showDialog.value = true;
    }

    return {
      showDialog,
      handleClick,
    };
  },
});
</script>
<template>
  <el-button @click="handleClick">{{ msg }}</el-button>
  <el-dialog :visable="showDialog">
    <div>...</div>
  </el-dialog>
</template>

将与按钮逻辑耦合的对话框组件组合在一起,避免在父组件中多个对话框组件,造成页面耦合度过高。

排序

业务上有一个需求是希望能够直观地对产品列表进行排序,让收益好的产品优先显示。针对这个需求,目前的方案是在管理后台通过给每个产品设定一个「排序值」,后台排序之后再返回给业务端显示。但是由于产品太多,运营人员希望能够实现拖拽排序。

管理后台页面的产品列表是使用 el-tree 组件实现的,它提供有拖拽的功能,于是就根据文档调试了一下。但是出现了一个问题。由于目前的排序值可能会有相同的值,当使用组件的拖拽排序时可能会导致目标位置的前后为同一个值,此时对于数据的排序就可能会出现错误。

但是在和运营更深入的沟通之后,了解到实际的需求其实是觉得无法直观的了解当前产品的排序,于是这个时候思路就可以打开了。

只要在 el-tree 组件中将各个元素的排序值显示出来,比如附在产品名称的结尾,运营人员就可以直观地为产品设置适当的排序值。这样可以在最小化改动的同时满足需求。运营人员对于这个改动也非常满意。

闽 ICP 备 2021009779 号 - 1 | Copyright © 2020 华丽 | Powered By Hugo