スケーラブルなシステムの開発は、ソフトウェア設計の11の原則を遵守しなければなりません

01シンプル

◆複雑さを隠し、抽象構築

システムの発展に伴い、あなたがより多くの複雑でしょう、システム全体のすべて、それぞれの人の脳の限られた処理能力を理解しないかもしれないが、システムのすべての詳細を知ることは不可能です。


したがって、簡単なソフトウェアを維持するために、あなたがより良いシステムを理解するのに役立ちます。システムの段階的な拡大に伴い、行うことができます我々は維持することです単に地元の全体的なシンプルさを維持することはできません。


抽象度の高いへの露出を作成するには、システムサービスを開発する場合、抽象的には、その複雑さを隠すために約束した機能を実現します。


オーバーデザイン◆回避

当社のエンジニアは、一般に、1つの簡単な質問を維持するのが難しいコードを開発することを可能にする、それが複雑になりますことが困難な問題の挑戦を好みます。早期抽象化の合理的なレベルを構築することができ、あなたはので、より多くの有益な複雑なシステムの設計と開発当初より、将来の繰り返しに新しい機能を追加することができます。


理解しやすいシンプルなシステムを開発し、将来がスケーラブルであることを証明することができますすることは現実的な問題です。


◆トライテスト駆動開発のTDD

TDD:テストドライブの開発。機能をプログラミングし、テストケースを書き、最初。


、ユーザの視点からの問題で明確かつシンプルなインタフェースを開発するためにヘルプをご覧ください。


簡素化するために設計されたソフトウェアの例から学びます◆

Grailsの(設計の詳細はシンプルで、簡単に拡張すること)、Hadoopの他(複雑な問題を解決する際に十分な柔軟性を確保するために、単純なAPI)、Google MapsのAPIを(非表示複雑な実装は、非常にシンプルなプログラミングAPIを提供):のような、システムやソフトウェアの知識から学びます。


良いデザインとソフトウェアのモードから学びます。


02低結合


私たちは、一般のシステムは、高い凝集と低カップリングされている求めています。これは、関連性の尺度であり、2つのシステム間の依存関係を結合します。高い結合の程度はLaiyue江で表されます。
カップリングのためのハイとローのカップリングシステムの影響を

①高いカップリングは、システムの他の部分は、コードを変更すると、問題の有無を確認する必要があります。

②低い結合のみモジュール内部の複雑さに反映され、地域の複合確保することができ、システム全体に影響を与えません。

③異なるサブシステムに切り離さ、システムの部品は、より多くのCPU又はIO以上のスループット能力、または複数のメモリアプリケーションを必要とするかもしれません。異なるアプリケーションのための優れたスケーラビリティ特性を達成するために、異なるハードウェア構成。


低カップリングを促進◆

低カップリングを促進するための最も重要な練習はあなたの依存を管理するように注意です例えば:,モジュール間、クラス間のアプリケーション間の依存関係。


不要な結合を避けます◆

カップリングの例としては、不要な避けるために:

①Java開発者のために、公共のセッターゲッターは、プライベートメンバ変数を暴露、メンバ変数を(IDEは、多くの場合、自動的にすべてのセッターとゲッター公開メンバ変数を生成するために、すべてのメンバ変数に使用されますがあります)公開する時々必要より一般的でありません。

②モジュールまたはクライアントエンドポイントのメソッド呼び出しのコードは、特定の順序でなければなりません。時には、これがためにAPIの貧弱な設計の合理的であるが、ほとんどの時間、メソッドシグネチャに影響を与えるだけでなく、メソッド呼び出し依存的に影響を与え、カップリングを増加させるだけでなく、依存しています。


暴露されると、ドメインへのアクセスを必要とするか、不要カップルと呼ばれているが発生する可能性があります。


◆疎結合パラダイム

低結合は、他の人のコードは、優れた経験を取得し理解することを学ぶことができます。
たとえば:; SLF4Jロギングフレームワーク、優れたオープンソースのソフトウェアを、というようにUNIXコマンドラインの使用方法とプログラミングパイプラインは、シンプルなAPIを公開しています。
良いソフトウェアのソースコードやデザインを学びます。低カップリングシステムを維持するために健康とスケーラブルなシステムのために不可欠です。低カップリングは、ソフトウェア開発の弾力性の最も基本的な原則の一つです。



03乾式Doが自分自身を繰り返しません


繰り返し一つは、非常に、価値のないものを退屈されます。何度も何度も繰り返し同じことは、単に人生の無駄です。


ソフトウェアエンジニアリングのライフサイクルでは、しばしば繰り返されるアプリケーションコードから、コードは試験前を毎回繰り返してリリースする、というように、重複したものに遭遇します。


繰り返し物事行う理由は

①非効率的なプロセスを使用して

在软件开发的过程中,设计、交付、开会等,持续对这些进行改进可以获得很好的收益,获得反馈、持续改进、然后重复这个过程。团队意识到很多都是在浪费时间并无可奈何。当你经常听到“本来就是这么干的”或“一直是这么干的”,那么往往说明这里有低效的过程并且有改进的机会。


②缺乏自动化

我们在开发的项目的过程中经常要做的事:手工部署、编译、测试、打包、配置等等。有时候你会发现你一整天的时间都消耗在了这些过程,但是你的新任务却没有开始,然后只能加班加点的完成新功能的开发了。如果有一套自动化的工具帮你做这些事,那就可以很好的完成工作了,而无需浪费时间在这些重复过程之上。


③重复造轮子

已有现有的功能代码,却非要自己重新来写一个,并且写的还没有别人好,bug贼多。比如:排序、b树、MVC框架或数据库抽象层。这完全就是在浪费时间,已有的类库和工具就可以方便和快速的帮助我们了。

④复制黏贴Ctrl C、Ctrl V

我们在开发过程中,或者看到别人写的代码也容易发现,在同一个项目里(或项目组系统内)会存在大量拷贝其它地方的代码,这种重复性的代码想必你一定不陌生,并且有的IDE工具也有这些提示重复代码的功能。虽然有时拷贝是最方便快捷的事,但是一旦出现需要变更、维护等,其不足就表现出来了:维护多份代码、遗漏修改,造成bug再次出现等等。

⑤持有凑合态度——代码不会再用第二次了

有时候我们开发时,容易出现认为这份代码目前只是拿来简单用用,然后就随便写写。并没有文档、单元测试、很好的设计、很难用。这样的代码可能会存在很多漏洞,也可能给其它人复制粘贴,同样会给别人造成巨大的“灾难”。


04基于约定的编程

基于约定编程,也就是基于接口编程。将客户端代码和功能提供者代码进行解耦合。
在设计代码的时候,尽可能创建明确的约定,也尽可能的依赖约定(而不是实现)进行开发。


现实技术领域中,基于约定编程的比较常见的便是HTTP协议,客户端Web浏览器:Firefox、Chrome、HTTP服务提供者:Apache、Tomcat等,都按照约定进行编程设计与开发,这样就能很好发挥HTTP的实现弹性和提供者透明的可替代性。


05画架构图

一图胜千言!
通过架构图可以将系统设计文档化、跟他人分享信息、帮助自己更好的了解自己的设计。


很多时候,我们接到需求就直接拿起编辑器进行功能开发,并没有做前期的分析和设计,特别是目前很多工程师在追求敏捷开发更加容易造成这样的处境。


有时我们开发好功能了,到最后可能发现自己写的代码是有问题,比如跟需求要求不一致、逻辑漏洞很多,因为糟糕的设计(基本没有设计),你最后可能也得重头再来,这个是很常见的开发风险问题,我们应该重视它。


常见的架构图:用例图、类图、模块图。

用例图:定义系统的用户是谁,可以执行哪些操作。

类图:类的信息、类与类之间的关系。

模块图:描述结构和依赖关系。抽象层次更高。

架构图是你对于功能系统的设计表现,可以从多个角度审视自己的设计,可以降低开发风险。


06单一职责

单一职责原则,你的类应该只有一个职责而不是更多。

作用:降低代码复杂度,降低耦合、增加简单性、易于重构、代码复用、单元测试。


改善单一职责的一般最佳实践:

①一个类的代码少于2-4屏;

②确保一个类依赖不超过5个接口或类;

③确保类有明确的目标;

④用一句话总结一个类的职责。


进一步掌握单一职责办法可以研究这些设计模式:策略、迭代器、代理、适配器等模式。


07开闭原则


开闭原则,当需求变更或者增加新功能时,无需修改现有代码。


向扩展开放,向修改关闭。


开闭原则常见优秀例子:排序算法-Comparator接口(只要继承此接口,实现具体的算法逻辑),MVC框架(扩展各种组件,无需修改原有代码)。


08依赖注入

依赖注入是一种降低耦合改善开闭特性的简单技术。依赖注入对类需要依赖的对象提供一个引用实例,无须类自己创建依赖对象。


依赖注入的思想:知道的越少越好。尽可能让类不需要知道如何去创建需要的依赖,以及依赖来自哪里,如何实现。


依赖注入一般不需要new实例,而是由依赖的对象实例提供。
使用得当的话依赖注入可以有效降低局部复杂度,使其更简单。不用知道实例从何而来,不用知道谁来提供依赖的实例,这样就可以更好的聚焦自己的职责。


推荐学习依赖注入的优秀框架:Spring、Grails等框架。


09控制反转

控制反转IOC是一种从类中移除职责的方法,从而使类更简单,与系统其它部分更少耦合,其核心就是不必知道是谁、怎样、何时创建和使用对象,尽可能简单易于理解,对于软件设计而言,各部分互相知道得越少越好。
学过Spring的都知道,依赖注入、控制反转是其主要核心思想。


好的IOC框架应该包含

①可以为框架开发插件。

②插件的独立的,可以随时插入移除。

③框架可以自动检测到插件,或者通过配置文件加载。

④框架为每种插件类型定义接口,而不会与其具体插件耦合。


10为伸缩而设计


每种伸缩和对应的方案实践之间都要仔细权衡,不要为了那些永远用不着的伸缩性需求进行过度设计,要认真评估系统最可能的实际伸缩性需求进行相应的设计。


在创业公司中,很多都没有做到任何系统可伸缩就倒闭了,所以我们应该在追求可伸缩性系统的同时也要实事求是根据业务发展情况进行调整,不能一味的追求完美的伸缩系统,而是要有大局观进行技术的规划和各项权衡等等。


讨论各种设计原则都是为了解决系统的耦合性和复杂性,这些原则大部分有助于我们改善系统的伸缩性。


伸缩系统设计方案主要是下面这三个基本的设计方法


◆增加副本

同一组件或者系统服务部署到多台机器上(集群)。


在Web层而言,增加副本是最容易、成本最低的伸缩方案,主要的挑战是对于有状态的服务难以使用这种方式,需要同步状态来实现副本任意可交换(正是如此,我们设计系统时一定要设计实现无状态的系统)。

◆功能分割

根据功能将系统拆分成粒度更细的子系统(特别是当前的微服务架构)。基础设施架构,服务器服务器进行分离部署:对象缓存服务器、消息队列服务器、Web服务器、数据存储服务器、负载均衡器等等。

功能分割更先进的方式:将系统分割成自给自足的应用。主要适用于Web服务层,是面向服务架构SOA的一种主要实践。

功能分割会带来很多好处也有缺点,分割后,最开始就会带来很多管理方面的问题还有相应的成本也会很高,我们也不可能无限制的进行分割,达到“适可而止”即可。这一方面可以了解下当前微服务架构技术。


◆数据分片

每台机器存储一部分数据(数据库分库分表等)。

数据分片+增加备份(副本),可以实现几乎是无限的伸缩性,只要能正确的切分,就能增加更多的用户,处理更多的并发连接,收集更多的数据,将系统部署在更多的机器上。

但是,数据分片是最复杂、代价最昂贵的技术。数据分片最大的调整是,数据在访问前,就得找到需要存储数据的所在分区的服务器,如果一个查询涉及到多个数据分区,实现起来就变得异常低效和困难了。

举个例子,比如现在的分布式数据库,或者分布式中间件(ShardingSphere),有很多框架或者系统在这方面都会存在问题或者实现起来麻烦,关键也会对性能上有很大的影响,所以有时就得权衡或者妥协各种问题。

为伸缩而设计,主要是要在这三个基本的设计方法:增加副本、功能分割、数据分片。
虽然有各种技术方法帮助或指导我们,但是实际上还会存在各种各样的问题需要我们去处理或者去权衡。


11自愈设计

一个系统高可用,是以用户的角度来看能够达到预期的运行,即使系统出现部分异常或者部分设备宕机,只要不影响用户使用。


我们都认为整个系统是可用的。


我们的系统越大,相应的失效概率就会更高。进行伸扩容时,失效也会变得更加频繁。设计一个伸缩性架构必须把各种失效状态当作常态,而不是特殊情况对待。


想要设计一个高可用系统,必须做最坏的准备才能得到最好的期待,要不停的假想哪里会报错出异常,然后是要怎么处理它。


我们应该如何识别失效单点问题?


一个简单的方法就是画出系统架构图,每个设备(路由器、服务器、交换机等网络基础设施)等要画上去,然后询问自己, 如果某个设备宕机时会发生什么,某个子系统挂了怎么办等。


当识别出实效单点后,就要和业务团队和基础技术团队开讨论如何做才能达到高可用,是否需要做哪些冗余(冗余在成本和是否复杂等方面需要仔细权衡)来做备份等等。


确保系统高可用的主要手段是消除失效单点的风险和优雅地进行失效转移。


推荐可以学习或了解相关技术:混沌技术(比如Netflix开发的Chaos Monkey、阿里开源混沌工程工具 ChaosBlade)、开源数据库Cassandra(很好的自愈处理能力),这些都极其优秀,值得一学。


设计软件一定要考虑高可用和系统自愈能力。

おすすめ

転載: www.cnblogs.com/yaoyinglong/p/11857854.html