You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

108 lines
11 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# 开篇词 | 软件设计,应对需求规模的“算法”
你好,我是郑晔!
作为一个能把基本功能实现出来的程序员,偶尔仰望天空时,你是否这样问过自己,“我写过的代码还有没有更好的写法呢?如果有一天,我能够把它重写一遍,我该怎么做呢?”
这就是我当年问过自己的问题,因为我对自己的代码不满意:
* 我厌倦了把各种代码堆砌在一起然后在出现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原则也是比较成体系的设计原则它本身也在不断发展。
**设计模式**,是设计原则在具体场景下的应用。不过,这个话题展开之后,内容会非常多,而且有很多书和课程都讲到了,所以,我并不准备把它当作重点。但我会和你分享一些学习设计模式的心得,帮助你将设计模式的相关知识贯穿起来。
当你手里有了诸多工具之后,接下来就需要用这些工具去做自己的设计了。这就轮到**设计方法**登场了。
我会用[领域驱动设计](https://time.geekbang.org/column/intro/100037301)(也就是 DDDDomain Driven Design进行讲解这是目前最为完整、有效的应对复杂业务场景的设计方法包括了从如何识别概念到如何建立模型。在这个课程中我准备将DDD的基础知识贯穿起来做一个结构性的介绍。你会发现有了前面知识的铺垫DDD理解起来一点都不困难。
有了基础知识,在课程最后,我们还会在**巩固篇**中操练一下将学到的软件知识应用起来。在这个模块中我会结合自己的开源项目Moco来讲讲如何设计一个程序库还会借着一个数据采集的项目谈谈如何构建起一个可扩展的模型。另外因为大多数人在实际工作中面对的都是一个既有的项目所以我还会讲讲如何对既有项目做设计上的改进。
![](https://static001.geekbang.org/resource/image/62/31/62edbd37324ea5b7af4da7c15b4d9431.jpg)
## 写在最后
最后,再自我介绍一下。我叫郑晔,一个从业近二十年的程序员,《[10x程序员工作法](https://time.geekbang.org/column/intro/100022301)》专栏作者。很高兴又回到极客时间,和你分享我对软件设计的理解。
如果说《10x 程序员工作法》这门课是在告诉你要做正确的事,做有价值的需求,别把时间浪费在不该做的事情上,那《软件设计之美》这门课就是告诉你如何把事做对,如何建立有效的模型,划清模块之间的边界,所以,二者可谓一脉相承。
不想当将军的士兵不是一个好士兵,不想做设计的程序员不是一个好程序员。写程序的人谁不想操刀一个大型的系统,但不懂软件设计的人能摆弄的代码规模是有限的,而这也限定了一个人的成长高度。
学习软件设计,是让你的把控能力从一段代码扩展到一个模块,再扩展到一个子系统,再扩展到一个大系统的必备手艺,是程序员从“家常菜厨师”到“大厨”的进阶之路。
不过,你也不必把软件设计想象得过于高大上,很多设计理念既可以用来设计一个系统,也可以运用于日常开发之中,它就在你的身边。今天多学习一点设计,明天就能多发现一个问题。
如果你曾与我一样,走入过软件开发的迷途;如果你希望自己的软件开发能力再上层楼;或者你只是对软件设计充满好奇,那么,欢迎加入我的课程。也欢迎你把自己的现状和预期写在留言区,当课程结束时,让我们共同见证你的成长!
你准备好了吗?让我们正式开启软件设计之旅,一起领略软件设计的美妙!