开篇词 软件设计,应对需求规模的“算法”
你好,我是郑晔!
作为一个能把基本功能实现出来的程序员,偶尔仰望天空时,你是否这样问过自己,“我写过的代码还有没有更好的写法呢?如果有一天,我能够把它重写一遍,我该怎么做呢?”
这就是我当年问过自己的问题,因为我对自己的代码不满意:
- 我厌倦了,把各种代码堆砌在一起,然后,在出现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 👍(48) 💬(1)
昨天看到一个段子。问:你去年写了十万行代码,今年怎么写的这么少? 答:因为我学会了使用 for 条件语句。😅
2020-05-25 - 夏天 👍(24) 💬(1)
需求的规模是增长的,当规模还不大的时候,需要用到设计吗?是不是crud就可以了?
2020-05-25 - Jxin 👍(12) 💬(1)
1.欢迎郑老师回来!! 2.去年学习10x时,菜得很,受益良多。今年在谈软件设计,已有不少实践,希望能真正参与到专栏中来,而不再只是仰望。 3.目前罗列的内容,知识面大了。相信郑老师主心骨应该还是串联这些个内容的骨干网络。但,细节与骨干实在不好把握,毕竟篇幅有限。有些许担忧。 4.望再创佳绩。共同进步。
2020-05-25 - 西西弗与卡夫卡 👍(12) 💬(1)
欢迎郑老师回来
2020-05-25 - 我能走多远 👍(5) 💬(1)
《10x程序员工作法》的忠实读者,受益非浅,解决了目前工作中的很多问题。如何管理上级,如何应对项目需求多变。说一下我工作中的一个例子:公司是中等公司,没有一套完整项目开发流程;项目文档和设计更没有;不同的人对功能的实现有不同的理解;代码开发遵循自己的想法,导致在代码review时候分歧很大。所以我改变了思路。必须先把设计放在前面,组织大家项目讨论设计思路。头脑风暴统一一个好的设计方案并文档记录。在review时候有分歧已文档为准。避免自己反复改动风险。《软件设计之美》一出,毫不犹豫的购买了。
2020-06-04 - 维搭小刘 👍(5) 💬(1)
《10x程序员工作法》真心写的好,老师的功底非常深厚,受益匪浅。里面的一些好的观点,自己以前也觉得应该这样,就是不知道对不对,老师的专栏让我非常坚信这些是对的,让我更能毫无顾虑地坚持下去。非常有幸能看到老师的第二个专栏,继续加油学习。
2020-05-28 - 许童童 👍(5) 💬(1)
老师,江湖又见
2020-05-26 - escray 👍(4) 💬(1)
我写过的代码还有没有更好的写法? 之前写的代码不多,做的项目也多是一次性的,所以没有机会长时间的维护代码。倒是有一个文本格式转换的小工具,来来回回的写了很多次,用过不同的方式去写,但是最终也不那么令人满意。 如果再写一次的话,估计会换成配置文件和文本解析的做法,应该可以满足后续的需求变化。 "软件设计是关注长期变化的学问”,那么 Web 开发是否算得上是长期? “算法对抗的是数据规模,软件设计对抗的是需求规模”,这个说法很精辟,我之前接触的多是项目式的开发,验收评审之后就不再做大的修改了,而几年之后会推到重来一次。但是,即使是在项目开发的过程中,也会遇到需求不断变更的情况。 之前在极客时间购买过《10X程序员工作法》,可惜的是并没有看完;而且从销售数据来看,类似这样的“软技能”课程似乎并不是特别受欢迎。但是在我看来,这两门课都是很有价值的,特别是对我这样的大龄求职者来说。 打算借着《软件设计之美》的更新,重读《10X程序员工作法》,然后再去找一份技术类的工作。 有一个问题比较好奇,如何衡量一个软件或者系统设计的好与不好呢?或者更直白一点讲,自己如何知道设计的好不好,进而如何让老板或者客户知道,我设计了一个“好”的软件。
2020-05-27 - 小钟 👍(4) 💬(1)
去年学习郑老师的10x时获益良多,所以看到这个课程就马上购买了,希望可以更多的学习一下基本功。
2020-05-26 - Jaising 👍(3) 💬(1)
欢迎郑老师回归!拜读10x程序员工作法只变成了2x程序员🤭继续努力再提升2x
2020-06-22 - 布衣骇客 👍(3) 💬(1)
热烈欢迎郑老师回归,10x已经度过两次多,收益多多,无脑支持!!!
2020-05-29 - 倡印 👍(3) 💬(1)
我是做游戏开发的,感觉现在的工程实现就跟随意,业务需求的诡异多变,工程上也没有专门的规范。老大也不在乎这些我感觉很苦恼。。。
2020-05-26 - 喵喵花花 👍(2) 💬(1)
我想从专栏里得到,「软件设计」不再是一个模糊概念的名词,而是对它具化后的一番景色。是入门人的指路灯。
2021-08-12 - jokar 👍(2) 💬(1)
“今天学一点设计,明天就能多加一点班”,我感觉自己应该换一份工作了。
2020-06-03 - Laughing 👍(2) 💬(1)
有朋友推荐过来,期待思维收益
2020-05-27