开篇词 | 软件设计,应对需求规模的“算法”

你好,我是郑晔!

作为一个能把基本功能实现出来的程序员,偶尔仰望天空时,你是否这样问过自己,“我写过的代码还有没有更好的写法呢?如果有一天,我能够把它重写一遍,我该怎么做呢?”

这就是我当年问过自己的问题,因为我对自己的代码不满意:

  • 我厌倦了,把各种代码堆砌在一起,然后,在出现Bug时,犹如“大家来找茬”一样在其中定位问题;
  • 我厌倦了,仅仅为了一个小需求,要在无数的地方小心翼翼地做着各种微调,还被产品经理嫌弃改得慢;
  • 我厌倦了,自己辛辛苦苦写好的代码,被别人在其他地方不经意地修改,给弄崩溃了;
  • ……

我四处寻找答案,直到后来,我找到了一个东西,叫做“软件设计”。在如饥似渴地学习了软件设计之后,我对做软件这件事有了全新的认识:

  • 我知道了,写软件不仅要追求如何实现功能,还要考虑未来的维护和扩展;
  • 我知道了,代码不应该毫无目的地堆在那里,而是要考虑如何组织更为恰当;
  • 我知道了,原来后期遇到很多问题,只是因为前期缺乏设计而留下了隐患;
  • ……

如果你也曾有同样的迷茫,想破茧成蝶,欢迎你与我一起探索“软件设计”!

关注长期变化的软件设计

设计是为了让软件在长期更容易适应变化。

Design is there to enable you to keep changing the software easily in the long term.

—— Kent Beck

软件设计,是一门关注长期变化的学问。它并不是程序员的入门第一课,因为初窥编程门径的程序员首先追求的是把一个功能实现出来,他无法看到一个软件长期的变化。

或许未曾学过软件设计,但这并不妨碍你凭借一股蛮力把软件写出来。但如果你在做的是一个有生命力的软件,长期意味着什么呢?意味着会有源源不断的需求扑面而来。面对一拨又一拨的需求,你该如何应对呢?

你可以想象一下,小米加步枪的解决方案,在敌人不多的时候,你还可以应付得游刃有余,但当敌人已经漫山遍野时,你需要的是大规模杀伤性武器。而软件设计就是这个大规模杀伤性武器。

用程序员们更熟悉的排序算法为例,快速排序的平均复杂度是O(nlogn),而插入排序是O(n^2)。所以,一般我们说快速排序比插入排序有优势。但是,这种优势只有在一定规模下才能体现出来。当数据规模很小的时候,二者差别并不明显,更有甚者,插入排序在某些情况下表现得会更好。但当数据规模很大时,快速排序的优势就非常明显了。对比两个算法的优劣,关键在于数据规模。

所以你会发现,算法和软件设计其实是一样的,二者对抗的都是规模问题,只不过,算法对抗的是数据的规模,而软件设计对抗的是需求的规模

你现在应该理解了,为什么软件设计是一门关注长期的学问了,因为只有长期的积累,需求才会累积,规模问题才会凸显出来。软件设计,实际上就是应对需求的“算法”

如何学习软件设计?

软件设计的相关知识有很多,你可能听说过一些,比如,设计模式、领域驱动设计等等。但是,分别学习这些知识时,总有一些令人困惑的地方。比方说,学了那么多设计模式,你能用上的却没有几个;领域驱动设计中的概念那么多,你都不知道该从哪学起。

你的困惑我也有过,我花了很长时间才知道,我们困惑的,并不是这些知识本身,而是在于缺乏一个整体结构将它们贯穿起来。比如,多态,这个词在你看来只是一个普通的语法规则,但只有你懂得,它是把变的部分和不变的部分隔离开来,你才能理解开放封闭、接口隔离和依赖倒置这些设计原则的价值所在,理解了这些原则,才能知道某些设计模式只是这些原则在具体场景下的应用。

也就是说,软件设计学习的难度,不在于一招一式,而在于融会贯通

所以,在这个课程中,我会尝试将软件设计的相关知识贯通起来,帮你建立起对软件设计的整体认知。

那具体要从哪里入手呢?其实对于“软件设计”,我们可以将其划分为两个维度:“了解现有软件的设计”和“自己设计一个软件”。

了解现有软件的设计,是能够在这个软件上继续添砖加瓦的前提。事实上,无论是初入职场,还是加入一个新公司,在工作初期,我们能做的往往也只是添砖加瓦,这时候如果能快速了解现有软件的设计,就可以尽快投入工作中去。此外,当你想从一个开源项目上汲取养分时,了解其背后的设计,也是一种不可或缺的能力。

大多数人在理解一个软件时,总会出现一个问题,就是眉毛胡子一把抓,直奔代码细节而去。这样不仅增加了我们的时间成本,还会迷失在细节之中,只见树木不见森林。所以在这个课程中,我会教你一个快速了解现有软件设计的方法,那就是抓住这个软件最核心的三个部分:模型、接口和实现

同时我会以一些开源项目为案例,教你如何用这个方法去解读它们的设计,比如:

  • 我们怎样理解Spring DI容器模型,它的模型怎样有效解决了其面对的问题;
  • 如何理解Ruby on Rails的接口,我们可以从其接口设计中借鉴哪些内容;
  • Kafka的实现有哪些独特之处,实现的诸多细节中,我们应该关注哪些内容。

通过对这些案例的解读,你会切实地感受到融会贯通的好处,真正做到快速了解一个软件的设计。

慢慢地,当你在业务和技能上有了一定的积累,你将有机会做属于自己的设计。你负责的工作内容也将会从一个小功能到一个完整的小业务,从到一个模块到一个系统。随着你的能力不断提升,你负责的内容会逐渐增多,复杂度逐步升级,对你设计能力的要求也会随之攀升。

这时,你就需要掌握一些软件设计的基础知识。我会把软件设计中最重要的部分交付给你,包括:

  • 程序设计语言;
  • 编程范式;
  • 设计原则;
  • 设计模式;
  • 设计方法。

程序设计语言,是软件设计落地的基础。任何设计都依赖程序设计语言来实现。但任何语言也都有自己的局限,我将带领你横跨语言学语言,让你不再局限于某一种语言,而是择其善者而从之,更好地落地你的设计。

编程范式,是代码编写的风格,决定着你在设计时可以用到哪些元素:是模块、是对象,还是函数。在不同层次的设计中,选择不同的编程范式已经成为今天开发的主流。在这个主题下,我选择了几个最主流的编程范式,包括结构化编程、面向对象和函数式编程,帮你建立起软件设计的根基。

设计原则,是你在进入到具体设计的层面时,可以用来评判自己工作结果的一个衡量标准。我会给你介绍面向对象的主流设计原则:SOLID原则。一来面向对象是当今的主流开发方式,二来SOLID原则也是比较成体系的设计原则,它本身也在不断发展。

设计模式,是设计原则在具体场景下的应用。不过,这个话题展开之后,内容会非常多,而且有很多书和课程都讲到了,所以,我并不准备把它当作重点。但我会和你分享一些学习设计模式的心得,帮助你将设计模式的相关知识贯穿起来。

当你手里有了诸多工具之后,接下来就需要用这些工具去做自己的设计了。这就轮到设计方法登场了。

我会用领域驱动设计(也就是 DDD,Domain Driven Design)进行讲解,这是目前最为完整、有效的应对复杂业务场景的设计方法,包括了从如何识别概念到如何建立模型。在这个课程中,我准备将DDD的基础知识贯穿起来,做一个结构性的介绍。你会发现,有了前面知识的铺垫,DDD理解起来一点都不困难。

有了基础知识,在课程最后,我们还会在巩固篇中操练一下,将学到的软件知识应用起来。在这个模块中,我会结合自己的开源项目Moco,来讲讲如何设计一个程序库;还会借着一个数据采集的项目,谈谈如何构建起一个可扩展的模型。另外,因为大多数人在实际工作中面对的都是一个既有的项目,所以,我还会讲讲,如何对既有项目做设计上的改进。

写在最后

最后,再自我介绍一下。我叫郑晔,一个从业近二十年的程序员,《10x程序员工作法》专栏作者。很高兴又回到极客时间,和你分享我对软件设计的理解。

如果说《10x 程序员工作法》这门课是在告诉你要做正确的事,做有价值的需求,别把时间浪费在不该做的事情上,那《软件设计之美》这门课就是告诉你如何把事做对,如何建立有效的模型,划清模块之间的边界,所以,二者可谓一脉相承。

不想当将军的士兵不是一个好士兵,不想做设计的程序员不是一个好程序员。写程序的人谁不想操刀一个大型的系统,但不懂软件设计的人能摆弄的代码规模是有限的,而这也限定了一个人的成长高度。

学习软件设计,是让你的把控能力从一段代码扩展到一个模块,再扩展到一个子系统,再扩展到一个大系统的必备手艺,是程序员从“家常菜厨师”到“大厨”的进阶之路。

不过,你也不必把软件设计想象得过于高大上,很多设计理念既可以用来设计一个系统,也可以运用于日常开发之中,它就在你的身边。今天多学习一点设计,明天就能多发现一个问题。

如果你曾与我一样,走入过软件开发的迷途;如果你希望自己的软件开发能力再上层楼;或者你只是对软件设计充满好奇,那么,欢迎加入我的课程。也欢迎你把自己的现状和预期写在留言区,当课程结束时,让我们共同见证你的成长!

你准备好了吗?让我们正式开启软件设计之旅,一起领略软件设计的美妙!

精选留言

  • Aliliin

    2020-05-25 21:38:39

    昨天看到一个段子。问:你去年写了十万行代码,今年怎么写的这么少?
    答:因为我学会了使用 for 条件语句。😅
    作者回复

    好段子,软件设计还真有这么个味道。

    2020-05-26 14:42:57

  • 夏天

    2020-05-25 17:56:03

    需求的规模是增长的,当规模还不大的时候,需要用到设计吗?是不是crud就可以了?
    作者回复

    学习设计的第一点是不给自己挖坑。如果不懂设计,起手就给自己留下很多坑,更可怕的是,自己意识不到。这与规模大小是无关的。

    CRUD 不是设计目标,而是一个结果,这是你懂了软件设计之后看到的,到如果不学习软件设计,你能做的就只是 CRUD 了。

    对于个人而言,需求规模不大时,你是可以掌控的,这是练习设计的好机会,等规模大起来,你想设计,可能就无能为力了。没有经过练习,就想上场比赛,还想取得好成绩,这是一种异想天开。

    2020-05-26 12:07:34

  • Jxin

    2020-05-25 22:35:05

    1.欢迎郑老师回来!!
    2.去年学习10x时,菜得很,受益良多。今年在谈软件设计,已有不少实践,希望能真正参与到专栏中来,而不再只是仰望。
    3.目前罗列的内容,知识面大了。相信郑老师主心骨应该还是串联这些个内容的骨干网络。但,细节与骨干实在不好把握,毕竟篇幅有限。有些许担忧。
    4.望再创佳绩。共同进步。
    作者回复

    哇,你太了解我的套路了,在我看来,建立起知识体系比什么都重要。有问题不妨发问,我能分享多少,就尽量分享多少。

    2020-05-26 14:45:38

  • 西西弗与卡夫卡

    2020-05-25 20:10:00

    欢迎郑老师回来
    作者回复

    欢迎继续分享你的经验!

    2020-05-26 11:41:35

  • 我能走多远

    2020-06-04 07:27:10

    《10x程序员工作法》的忠实读者,受益非浅,解决了目前工作中的很多问题。如何管理上级,如何应对项目需求多变。说一下我工作中的一个例子:公司是中等公司,没有一套完整项目开发流程;项目文档和设计更没有;不同的人对功能的实现有不同的理解;代码开发遵循自己的想法,导致在代码review时候分歧很大。所以我改变了思路。必须先把设计放在前面,组织大家项目讨论设计思路。头脑风暴统一一个好的设计方案并文档记录。在review时候有分歧已文档为准。避免自己反复改动风险。《软件设计之美》一出,毫不犹豫的购买了。
    作者回复

    欢迎回来,我们一起继续前行!

    2020-06-04 13:40:48

  • 维搭小刘

    2020-05-28 08:19:49

    《10x程序员工作法》真心写的好,老师的功底非常深厚,受益匪浅。里面的一些好的观点,自己以前也觉得应该这样,就是不知道对不对,老师的专栏让我非常坚信这些是对的,让我更能毫无顾虑地坚持下去。非常有幸能看到老师的第二个专栏,继续加油学习。
    作者回复

    我努力让这个专栏不辜负你!

    2020-05-28 09:53:23

  • 许童童

    2020-05-26 14:18:28

    老师,江湖又见
    作者回复

    有你们真好!

    2020-05-26 23:04:51

  • escray

    2020-05-27 14:38:05

    我写过的代码还有没有更好的写法?

    之前写的代码不多,做的项目也多是一次性的,所以没有机会长时间的维护代码。倒是有一个文本格式转换的小工具,来来回回的写了很多次,用过不同的方式去写,但是最终也不那么令人满意。

    如果再写一次的话,估计会换成配置文件和文本解析的做法,应该可以满足后续的需求变化。

    "软件设计是关注长期变化的学问”,那么 Web 开发是否算得上是长期?

    “算法对抗的是数据规模,软件设计对抗的是需求规模”,这个说法很精辟,我之前接触的多是项目式的开发,验收评审之后就不再做大的修改了,而几年之后会推到重来一次。但是,即使是在项目开发的过程中,也会遇到需求不断变更的情况。

    之前在极客时间购买过《10X程序员工作法》,可惜的是并没有看完;而且从销售数据来看,类似这样的“软技能”课程似乎并不是特别受欢迎。但是在我看来,这两门课都是很有价值的,特别是对我这样的大龄求职者来说。

    打算借着《软件设计之美》的更新,重读《10X程序员工作法》,然后再去找一份技术类的工作。

    有一个问题比较好奇,如何衡量一个软件或者系统设计的好与不好呢?或者更直白一点讲,自己如何知道设计的好不好,进而如何让老板或者客户知道,我设计了一个“好”的软件。
    作者回复

    非常感谢你的分享!

    先说Web开发是否算长期。其实这与Web开发无关,与软件生命力有关,这其实与业务的发展更相关。

    衡量一个软件设计好不好,最简单的外在标准就是看实现一个新功能所需的时间。内在标准就是用各种设计原则去衡量。

    2020-05-27 19:24:01

  • 小钟

    2020-05-26 18:27:22

    去年学习郑老师的10x时获益良多,所以看到这个课程就马上购买了,希望可以更多的学习一下基本功。
    作者回复

    欢迎回来!

    2020-05-26 23:03:51

  • Jaising

    2020-06-22 08:45:38

    欢迎郑老师回归!拜读10x程序员工作法只变成了2x程序员🤭继续努力再提升2x
    作者回复

    加油!

    2020-06-22 10:30:42

  • 布衣骇客

    2020-05-29 15:36:54

    热烈欢迎郑老师回归,10x已经度过两次多,收益多多,无脑支持!!!
    作者回复

    我们继续一起前行!

    2020-05-29 20:18:46

  • 倡印

    2020-05-26 10:33:46

    我是做游戏开发的,感觉现在的工程实现就跟随意,业务需求的诡异多变,工程上也没有专门的规范。老大也不在乎这些我感觉很苦恼。。。
    作者回复

    先看《10x 程序员工作法》,解决人的问题,再来说设计怎么做。

    2020-05-27 21:28:20

  • 喵喵花花

    2021-08-12 08:02:33

    我想从专栏里得到,「软件设计」不再是一个模糊概念的名词,而是对它具化后的一番景色。是入门人的指路灯。
    作者回复

    希望对你有所帮助

    2021-08-16 19:34:14

  • jokar

    2020-06-03 09:31:16

    “今天学一点设计,明天就能多加一点班”,我感觉自己应该换一份工作了。
    作者回复

    找一个对自己有一点挑战,能够让自己不断成长的工作很重要。

    2020-06-03 18:56:58

  • Laughing

    2020-05-27 11:49:35

    有朋友推荐过来,期待思维收益
    作者回复

    我努力不负重托!

    2020-05-27 20:36:53

  • Geek_bdd0e7

    2020-05-25 19:12:20

    我一直很想学习一下在编程中如何从定义到属性到定理到模型再到模型间的关系,最后从模块构建一个系统。

    当中有令人兴奋的地方。
    作者回复

    来,我们一起成长!

    2020-05-26 19:07:10

  • 术子米德

    2023-09-27 07:40:28

    🤔☕️🤔☕️🤔
    【R】实现基本功能之后,是否会问自己,还有更好的解法嘛?如果有机会再做一次,会做得怎样?
    【.I.】自己写的代码,写完后的半小时内很满意,然后就开始越看越不顺眼,为何?一方面问题得到解决,另一方面是冒出新问题,现有的解决方案不够完美,咋办?为何会有问题解决还不够完美的情况发生?谁会给重做的机会,谁又是因为什么原因才给出这样的机会,谁又在等待和渴望这样的机会?问题霹雳啪啦冒出来。
    【R】设计是为了让软件在长期更容易适应变化(Design is there to enable you to keep changing the software easily in the long term —— Kent Beck)。
    【R】软件设计是应对规模需求的算法 = 模型 + 接口 + 实现 = 程序语言 + 编程范式 + 设计原则 + 设计模式 + 设计方法。
    【.I.】如果软件写完就满足当下,那就盯住当下先来个版本,如果想不清楚未来是怎样,那也先写出个版本出来。只有写出版本,才知道当下这关能不能过去,再去设想未来有哪些关卡可能存在,更会有基本盘信心、也更可行些。最尴尬的往往是当下这关还没过,已经设想未来的各种波澜壮阔,结果却是深陷在当下这关再也没出来。反而是想不清未来怎样,先过好当下这关,遇到新变化后,用告诉自己原来这些自己的确想不到的诚恳姿态,更能够面对变化带来的改动,甚至不得不重新打地基。而这不正是更好的再做一次的原因和机会。再退一步想,只要未来有很多变化涌入,正表示此方面的需求和机会很多,这也是能够获取到更多资源的必要条件。最闹心的就是,啥都准备好了,就像个万事具备的胖子,眼看风来带走一切,只留下自己在那里凌乱。
    【Q】编程小白,直接上手干,边干边学边反思,还是,学好基本功,上手不挖坑,哪种更值得探索?
    ---- by 术子米德@2023年9月27日
  • 人月聊IT

    2021-05-05 08:18:44

    被十倍程序员吸粉的我,买买买
    作者回复

    加油啊!

    2021-05-08 08:00:39

  • 2020-08-19 01:20:54

    算法对抗的是数据的规模,而软件设计对抗的是需求的规模。这句话触动了我。
  • 0xABC

    2020-05-27 19:19:10

    等待好久,终于等到你
    作者回复

    让我们继续一起前行!

    2020-05-27 20:16:36