目录
-
前言
作为一名程序员,我们特别擅长用编程语言实现一个个系统功能。但是我们非常头疼产品同学一次次提出的需求变更。因为需求变更会导致程序员对已有代码进行改造,如果是自己的代码还稍微好一些,要是改他人的代码,估计心中一定有无数奔腾的草泥马。为什么维护老代码会这么的痛苦呢?当我们面对一堆陌生而复杂的代码时往往不知所措,看不懂代码思路,不知道业务逻辑,不知道修改后会不会影响其他逻辑。所以程序员喜欢做新项目和新功能,不愿意维护老系统和他人的代码。
怎么才能让维护老代码不成为又一个程序员噩梦呢?最理想的办法就是需求确认后就永远不要发生变化,这种情况肯定是不可能的。我们只能让代码更加优秀,在面对需求变化的时候,维护起来很容易。所以人们发明了许多理论来解决这个问题。
首先是开发模型从传统的瀑布模型转变为敏捷开发模型;
其次编程思想从面向过程编程转变为面向对象编程;
最后优秀的代码都是重构出来的,人们总结出了重构原则和设计模式。
-
软件开发模型
软件开发模型是从传统建筑工程借鉴来的,就是瀑布模型,大概的过程是需求分析、产品设计、系统设计、系统研发、系统测试、系统发布。最初瀑布模型很好的满足了需求,但是后来它就导致了很多软件项目的失败。失败的原因很多,比较典型的就是开发周期过长导致软件已经过时无法满足新需求。
为了缩短开发周期和应对需求变化,人们提出了敏捷开发理论,大概思想是简化初始需求,快速迭代演化,降低试错成本。需求和市场是不断变化的,软件产品不断快速升级来应对变化。目前来看敏捷开发模型符合实际研发需求。迭代与迭代之间的空隙给重构代码提供了机会,可以让代码不断优化。
敏捷开发
敏捷开发的迭代对象是故事。将一个大故事拆分成多个小故事,然后分成多次迭代周期进行实现。
故事三要素:
1.角色:谁要使用这个功能。
2.功能:需要完成什么样的功能。
3.价值:为什么需要这个功能,这个功能带来什么样的价值。
故事表达格式:
英文:As a <Role>, I want to <Activity>, so that <Business Value>.
中文:作为一个<角色>, 我想要<功能>, 以便于<商业价值>
举例:“作为招聘网站注册用户,我想要查看最近3天发布的招聘信息,以便于我看到最新的招聘信息”。
理想的用户故事是这样子的:
企业可以发布商品。
用户可以搜索商品。
用户可以使用信用卡付款。
-
面向对象编程思想
敏捷开发模型从项目开发过程提出了解决方案,但是编程思想也出现了问题。人们一直以来都是以计算机的思维在编写程序,就是所谓的面向过程编程思想。这导致程序代码让人理解起来非常困难,从而造成维护和扩展困难,没办法开发出大规模复杂软件,这就是著名的软件危机。
为什么不用人的思维方式编程呢?一切事物皆对象。人的思维方式就是对象思维。于是人们发明了面向对象编程语言。
面向对象编程有4个优点:可维护性,可扩展性,可复用性,灵活性。
面向对象编程的3个特征:封装、继承、多态。
《大话设计模式》中有一个非常生动的比喻,就是活字印刷术。调版印刷就是面向过程编程,一次性雕刻之后无法修改(维护性)、无法扩展(扩展性)、无法复用(复用性)、无法重新排版(灵活性)。活字印刷术就解决了上面的4个缺点,把每个字做出单独的模块(封装),可以随意组合成不同的文章和重复使用。所以面向对象编程能很好的应对需求变化。
-
代码重构
我们一直有一个误解,以为使用的面向对象语言就是面向对象编程。开发时常常创建一个类之后在“main()”里面把程序逻辑一次性完成,其实这就是典型的面向过程编程,一旦面对需求变化时就必须修改已有代码。当然完全不修改代码也是做不到的,所以我们需要一些编程原则来指导怎么写代码才能最小化修改代码。
前面提到过“优秀的代码都是重构出来的”,敏捷开发思想让我们快速实现功能是正确的,但是遇到变化之后需要对已有代码先做重构优化,然后才进行业务逻辑修改。大神们已经给我们总结出了经典的重构原则,我们只需要学习掌握就可以了。
重构原则:
- 单一职责原则SRP:只有一个引起变化的原因。
- 开放-封闭原则OCP:软件实体只能扩展,不能修改。
- 依赖倒转原则:针对接口编程,不要对实现编程。分层思想。
- 里氏代换原则LSP:子类必须替换掉父类。
- 迪米特法则LoD:最少知识原则。
- 组合/聚合复用原则:多用组合(Composition)和聚合(Aggregation),少用继承。组合是局部与整体的关系。聚合是包含关系。案例:大雁-雁群(聚合);大雁-翅膀(组合)。
- 敏捷开发原则:不要实现猜测和不需要的功能。
这些原则都很抽象,大家自己慢慢研究体会。另外重构也是一个重要的理论,需要配合单元测试来保证重构之后的代码不影响现有功能。
-
设计模式
铺垫了这么久,终于可以介绍设计模式了。所谓设计模式就是人们在重构过程中,总结出来的编程套路。这些套路可以满足面向对象的4个特性,让程序能很好的应对需求变化。
经典的设计模式有23种,解决3个方面的问题:对象创建、对象结构、对象行为,对应的把设计模式分为3个大类,创建型、结构型、行为型。
创建型:简单工厂模式、工厂方法模式、抽象工厂模式、单例模式、原型模式、建造者模式。
结构型:装饰模式、代理模式、外观模式、适配器模式、组合模式、桥接模式、享元模式。
行为型:策略模式、模板方法模式、观察者模式、状态模式、备忘录模式、命令模式、职责模式、中介者模式、解释器模式、访问者模式。
每种设计模式都有一个应用场景,解决特定的需求变化,没有一个万能设计模式可以解决所有变化。所以我们在学习设计模式时,根据自己的实际需要先掌握一些常用模式。那么用什么工具来描述设计模式呢?人们发明了UML来对软件设计进行描述。设计模式用到了类图。UML全名叫统一建模语言,一共有3类模型,功能模型、对象模型、动态模型。
UML模型:
- 用例图:从用户角度描述系统功能。
- 类图:描述系统中类的静态结构。
- 对象图:系统中的多个对象在某一时刻的状态。
- 状态图:是描述状态到状态控制流,常用于动态特性建模
- 活动图:描述了业务实现用例的工作流程
- 顺序图:对象之间的动态合作关系,强调对象发送消息的顺序,同时显示对象之间的交互
- 协作图:描述对象之间的协助关系
- 构件图:一种特殊的UML图来描述系统的静态实现视图
- 部署图:定义系统中软硬件的物理体系结构
- 包图:对构成系统的模型元素进行分组整理的图
- 时序图: 表示生命线状态变化的图
- 组合结构图:表示类或者构建内部结构的图
- 交互概览图:用活动图来表示多个交互之间的控制关系的图
-
总结
有同学估计要问,我们日常开发工作中有必要搞这么繁琐的设计步骤吗?一会敏捷开发理论,一会面向对象思想,一会重构、设计模式、UML图等等。我们平时开发工作都是直接撸起袖子就开干。大师们已经很好的回答了这个问题,有一个生动的比喻,建造一个茅草屋、一个别墅、一个摩天大楼,项目的开发模式是不一样的。敏捷和架构都一样,选择当前最适合的方案,而不是最先进的方案,不要过度设计。
程序员作为技术人员往往专注战术层面的问题,如何用最好的技术来实现软件功能。但是从战略层次来看,软件的本质是解决问题的工具,技术也是一种抽象的开发工具。如果想让自己不成为只会CRUD的程序员,就需要提升自己的思维层次,站在更高的视角来看待软件编程这个工作。