ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
[TOC] ## 程序组织 维护"设计的缘由"与维护"设计本身"一样重要 架构应该定义程序的主要构造块(building blocks),根据程序规模不同,哥哥构造块可能是单个类,也可能是由许多类组成的一个子系统 ## 主要的类 架构应该详细定义所用的主要的类 它应该住处每个主要类的责任 ,以及该类如何与其他类交互. 它应该包含对类的继承体系,状态转换,对象持久化等 架构应该记诉曾经考虑过的其他类的设计方案,并给出选用当前的组织架构的理由,架构无须说明系统中的每个类. 瞄准80/20 法则,对系统构成系统的80%的行为20%的类进行详细说明 ## 数据设计 架构应该描述所用的主要文件和数据表的设计, 数据通常只应该有一个子系统或一个类直接访问:例外的情况就是通过访问器,或访问器子程序--以受控且抽象的方式来访问数据, ## 业务规则 架构依赖于特定的业务规则,那么它就应该详细秒速这些规则,病描述这些规则对系统设计的影响 ## 用户界面设计 用户界面常常在需求阶段进行详细说明. 架构应该模块化,以便在替换为新用户界面时不影响业务规则和程序的输出部门 例如: 架构应该使用我们很容易地做到:砍掉交互式界面的类,插入一组命令行的类 ## 资源管理 架构应该描述一份管理稀缺资源的计划 稀缺资源包括: 数据库连接,线程句柄等, 在内存受限的应用领域,如驱动程序和嵌入系统中,内存管理是架构应该认真对待的另一个重要领域 架构应该估算在正常情况和极端情况下的资源使用量 ## 安全性 描述实现设计层面和代码层面的安全性的方法 在架构阶段接力威胁模型,在孩子定编码规范的时候应该把安全性牢记在心,包括处理缓存区的方法,处理非受信数据(用户输入的数据,cookies,配置数据(文件),和其他外部接口输入的数据)的规则,加密,错误消息的细致程度,保护内存中的秘密数据,以及其他事项 ## 性能 性能目标可以包括资源的使用,定义资源(速度,内存,成本)之间的优先顺序 如果为了满足性能目标,需要在某些部门使用特定的算法或数据类型,架构在应该说清楚,架构中也可以各个类或各个对象的空间和时间的预算 ## 可伸缩性 是指系统增长以满足未来需求的能力 架构应该描述系统如何应对用户数量,服务器数量,网络节点数量,数据库记录数,数据库记录的长度,交易量等的增长 ## 互用性 如果预计这个系统与其他软件或硬件共享数据库或资源,架构应该描述如何完成这一任务 ## 国际化 / 本地化 国际化常常成为"I18n",因为国际化的英文单词"Internationalization", 因为首尾两个字符"I"和"N"之间一共有18个字母 本地化成为"L10n"(Localization) 大多数交互系统包含几十上百条提示,状态显示,帮助信息,错误信息,等等.还应该表现出考虑典型的字符串问题和字符集问题,包括所用的字符集(ASCII,DBCS,EBCDIC,MDCS,Unicode,ISO 8859), 架构可以决定,在需要的时候,是在代码中直接嵌入字符串,还是将这些字符串封装入某个类,并通过类的接口来使用它, ## 输入输出 架构应该详细定义读取策略(reading scheme)是先做(look-achcad),后做(look-bechind) 还是即时做(just-in-time) 而且应该描述在哪里航检测I/O错误:在字段,记录,流,或者文件的层次 ## 错误处理 错误处理已被证实为现代计算机科学, 估计程序中高达90%用来处理异常情况,进行错误处理,或做薄记,,所以需要一种"一致的处理错误"的策略 错误处理常备视为"代码约定层次/coding-convention-level"的事情 要考虑的问题: 1. 错误处理是进行纠正还是仅仅进行检测.如果是纠正,程序可以尝试从错误中恢复过来,如果是检测,那么程序可以像"没有发生任何事"一样继续运行,也可以退出 2. 错误检测是主动还是被动的.系统可以主动的预测错误(如:通过检测用户输入的有效性,也可以在不能避免错误的时候,被动的相应错误) 3. 程序如何传播错误,可以立即丢弃引发该错误的数据,也可以把这个错误当成一个错误,并进入处理状态,或者可以等到所有处理完成,在通知用户说在某个地方发现了错误 4. 错误消息的处理有什么约定,架构要定义一致的错误策略 5. 如何处理异常(exceptions),架构应该规定代码合适能抛出异常,在什么地方捕获异常,如何记录log这些异常, 在程序中,在什么乘次上处理错误,可以在发现错误的地方处理,可以将错误传递到专门处理的类进行处理,或者沿着函数调用链往上传递错误. ## 容错性 架构还应该详细定义所期望的容错种类 容错是增强系统可靠性的一组技术,包括检测错误,如果可能的话从错误中恢复,如果不能从错误中的恢复,则包容其实不影响 举例: 1. 系统在检测到错误的时候退回去,在试一次,如果第一次的结果是错误的,那么系统可以退回到之前一切正常的时刻,然后从该点继续运行 2. 系统有用一套辅助代码,以备在主代码出错的错误使用,本例中,如果发现第一次的答案似乎有错,系统就切换到另一个计算平方根的子程序,以取而代之 3. 系统可以有一种表决算法,它可以有三个计算平方根,每一个都使用不同的计算方法,每个类分别计算平方根,然后系统对结果进行比较,根据系统内建的容错机制的种类系统可以以三个结果的均值,中值,或众数作为最终结果 4. 系统使用某个不会对系统其余部分产生部分产生畏寒的虚假值(phoney value)代替这个错误的值 其他容错的方法包括,再遇到错误的时候,让系统转入某种"部分运转/partail operation"的状态,或转入某种"功能退化/degrader functionaity" 系统可以自动关闭或重启, ## 架构的可行性 架构应该论证系统的技术可行性。 如果在任何一个方面不可行都会导致项目无法实施,那么架构应该说明“这些问题是如何经过研究的”—通过验证概念的原型( proof-of-conceptprototype)、研究、或其他手段。必须在全面开展构建之前解决掉这些风险。 ## 过度工程 健壮性(robustness)是指"系统在检测到错误后继续进行"的能力,如果组成系统的各个部门都只能在最低限度上满足健壮性要求,name系统整体上达不到所要求的的健壮程度的. 在软件中,链条的强度不是取决于最薄弱的一环,而是等于所有薄弱环节的乘积. 架构应该清楚的指出程序员应该为了"为了谨慎起见宁可进行过度的工程(overengineering)",还是应该做出最简单的能工作的东西. 详细定义过度工程(裕度工程)的方法尤其重要,因为许多程序员出于专业自豪感,对自己编写的类过度工程 ## 关于复用的决策 如果开发计划提倡使用业已存在的软件、测试用例、数据格式或其他原料架构应该说明:如何对复用的软件进行加工,使之符合其他架构目标——如果需要使之符合的话。 ## 变更策略 构建软件产品是一个学习的过程. 架构应该清楚的秒速处理变更的策略,并说明"最有可能增强的功能同样也是最容易实现的" 架构应该指出"延迟提交/delay commitment"所用的策略,比如说,架构也许规定使用表驱动(而不使用编码的if 语句),它也许还规定"表"中的数据是保存在外部文件中,而非直接写在程序代码中,这样就能做到在不重新编译的下修改程序 ## 架构的总体质量 架构应该是带有少许特别附加物的精炼且完整的概念体系 大型系统的本质问题是维持其概念完整性 架构的目标应该清楚的表达,以系统的可更改性(modifiability)为首要目标设计与以性能方面绝不妥协为首要目标的设计肯定是不同的--即便两个系统的功能完全一样 优秀的软件架构很大程度上是与机器和编程语言无关的,要尽可能地独立于环境 这样你就能抵抗对系统进行过度的架构的诱惑,也避免提前去做那些放到架构设计起见能做到更好的工作 架构应该在对系统"欠描述/underspecifying"和"过度描述/oversoecifying"之间的那条分界线.