2020 Google开发者大会重磅开幕 了解详情

十个有用的软件开发原则

2020 年 11 月 12 日

十个有用的软件开发原则

我总结了一些软件开发原则。在这些原则中,大多数都是以简化系统为核心。在我看来,简单的系统会更可靠,更容易修改,而且一般更容易使用。当观念发生改变时,我希望更新它们。


剔除无效状态


我把这一点排第一,是因为我认为它是最重要、最强大的原则之一。


你可能在定义类型时听到过这个词,但其实这个原则适用于所有与表示数据相关的地方——例如数据库设计。


它不仅可以减少系统的状态数量(从而变得更简单),还能减少无效状态的数量!你的系统不需要处理这些无效状态,因为它们在你的程序中实际上是不可表示的。


这不只是一个小技巧,它可以极大简化你的系统,并防止出现各种类型的 bug。这有一些例子


数据一致性让系统更简单


对数据施加一致性规则,减少了系统需要处理的状态数量。这是从上一个原则派生而来的。


定义


这里说的是一致性的普遍含义:即数据遵循某些规则,并且在任意时刻都始终遵循这些规则。这一定义与 ACID 有关,但不要与 CAP 混淆起来了。


规则可以是任何东西,例如,你的信用永远不能变成负数,或者私密的帖子不应该被其他人看到。它不仅限于外键或惟一索引,尽管它们也是有效的规则。


和数据库一样,应用程序也可以通过使用 ACID 事务来加强一致性。如果能在数据库级别强制保持一致性是最好的,但在实际中,对稍微复杂一点的东西来说,这样做并不常见。


实用建议


任何限制或损害一致性的行为都会导致复杂性。这就引出了以下这些实用的建议:


让系统更简单:


  • 更少的数据库(理想情况下是一个)

  • 规范化,减少冗余数据

  • 一个“好的”数据库设计

  • ACID事务

  • 更多的数据约束


让系统更复杂:


  • 多个数据库

  • 冗余或非正规化数据

  • 糟糕的数据库设计

  • 较少(或没有)数据约束


当然,有时候让系统变复杂也是有正当理由的,我并不想让复杂性变成一个“肮脏的”词。请参阅后面的一个原则“杀鸡不要用牛刀”。


我认为这个原则是当今软件工程中最被低估的原则之一。一致性问题经常被忽视。很多问题,我敢说大多数问题,基本上都是一致性问题——数据不符合某些期望。


参见附录,了解不一致性是如何导致复杂性的。


数据设计先行


这个问题,“代码还是数据?”,哪一个在 10 年后更有可能继续存在。


代码可以被丢掉重写,但数据很少会这样。


数据比代码更重要。代码的唯一目的是转换数据。


在设计新系统时,最好先从数据库和数据结构开始,并在此基础上开发代码。要考虑可以在数据上施加的约束并实施它们,理想情况下是通过表示数据的方式进行的。


代码设计是数据设计的下一步。数据模型越简单、越一致,代码就会越简单。


你们把流程图给我看,但把表藏起来,我就一头雾水。你们把表给我看,通常我就不需要你们的流程图,它们会不言自明。—— Fred Brooks


糟糕的程序员关心代码。好的程序员关心数据结构和它们之间的关系。—— Linux之父Linus Torvalds


杀鸡不要用牛刀


这是软件开发人员最常犯的错误。


这个原则是说,当你在做需要付出复杂性代价的权衡时,要确保权衡的必要性得到经验证据的支持。


常见错误:


  • 试图构建一个复杂的“可伸缩”系统,可以伸缩到你可能永远都不需要的规模。

  • 在不考虑需求或成本的情况下,让服务尽可能地小。

  • 在非性能瓶颈的地方优化性能,增加不一致性或复杂性。


建议:


  • 尽可能从最简单、最正确的系统开始

  • 对性能进行度量

  • 如果不能解决实际问题,就不要付出复杂性代价或违反其他原则。

  • 有些优化可以不进行度量,因为它们的成本非常低或为零。例如,为了保证你想要执行的操作具有你想要的性能,使用正确的数据结构。

  • 的确,有时候经验本身就能告诉你是否做出了正确的权衡。但如果你能证明,那就更好了。

  • 当你必须做出选择时,请选择正确性和简单性,而不是性能。

  • 在某些情况下,正确而简单的代码是性能最好的代码!


真正的问题是程序员在错误的地方和错误的时间花了太多的时间在担心效率上。过早优化是编程中所有(或者至少是大部分)罪恶的根源。——计算机科学家Donald Knuth


避免为了局部简单性而增加全局复杂性


也就是避免为了让系统的一部分变得更简单,而导致整个系统变得更复杂。


这种交换通常是不平等的。追求局部的简单性会导致全局复杂性的增加,而且是数量级的。


例如,使用较小的服务可以让这些服务变得更简单,但一致性的降低和对更多进程间通信的需求让系统变得更加复杂。


识别内在的复杂性


有时候事情本身就很复杂,你不能把问题简单化。


任何这样的尝试都只会让系统变得更加复杂。


使用的技术越少,系统就越简单


深入理解一小部分技术要比只是表面理解很多技术好。


更少的技术意味着更少的东西要学习和更少的运维复杂性。


集中精力学习概念,而不是技术


不要太关心技术的复杂细节,因为你可以随时查阅它们。你要学习底层的基本概念。


技术会变化,概念却是永恒的。你学到的概念将被用在更新的技术中,你就可以更快地学会新技术。


例如,不要太关注 React、Kubernetes、Haskell、Rust 的表面细节。


重点学习:


  • 纯函数式编程

  • 关系型模型

  • 规范的方法

  • 逻辑编程

  • 代数数据类型

  • 类型类(通用的和特定的)

  • 借位检查器(仿射/线性类型)

  • 依赖类型

  • Curry-Howard同构

  • 同像性(Homoiconicity)

  • VirtualDOM

  • 线性回归

  • ......


代码一致性很重要


有时候,具有一致性的代码比“正确”的代码更重要。如果你想要改变代码库中某些代码的行为,就要修改它所有的实例。否则的话,就只能忍受。


代码的可读性更多地与一致性(而不是简单性)有关。人们通过模式识别来理解代码,所以请重复(和记录)模式!


分享原则很重要


如果你和队友之间的共同原则越多,就能越好地在一起工作,而且你会越喜欢和他们在一起工作。


附录:不一致性导致的复杂性


这是我能想到的最简单的例子,希望能毫不费力地与现实问题联系起来。


假设一个数据库有两个布尔变量 x 和 y,你的应用程序有一个规则,即 x = y,可以通过使用一个事务修改这两个变量来执行这个规则。


如果这个规则被正确执行,那么数据只有两种状态:(x = True,y = True)或(x = False,y = False)。


基于这个规则的函数“toggle”就非常简单。你可以读取其中一个值,并将两个值都设置为反向值。


现在,假设你将这两个变量放到不同的数据库中,并且不能再被一起修改,那么会发生什么?


因为你不能确保 x = y 的一致性,所以数据可以有两种以上的状态:(x = True,y = False)或(x = False,y = True)。


  • 如果你的系统处于这些状态中的一种,你应该使用哪个值?

  • 当处于其中的一种状态时,“toggle”函数的行为是怎样的?

  • 在写入新值时,如何确保两次写入都成功?


这些问题没有正确的答案。


当然,如果我们一开始就遵循“剔除无效状态”的原则,那么将只有一个变量!


原文链接:


https://kevinmahoney.co.uk/articles/my-principles-for-building-software/

2020 年 11 月 12 日 13:45 1272
用户头像

发布了 41 篇内容, 共 57922 次阅读, 收获喜欢 70 次。

关注

评论 1 条评论

发布
用户头像
如果简单系统,你可以采用尽可能简单的技术,但是绝大部分系统复杂性都很高,他们还是避免不了采用复杂设计例如采用微服务,这样话,他违反上面很多原则,复杂系统能用简单方法实现,而且满足他们各种各样的非功能性需求,这个太罕见了
2020 年 11 月 12 日 17:00
回复
没有更多评论了
发现更多内容

释放数据价值:DAYU数据运营新能力解读

华为云开发者社区

大数据 数字化转型 华为云 代码原理 数据运营

大数据作用

非传统的“易观”,和他的技术驱动之路

易观大数据

阿里巴巴Java开发手册-日志规约

魏杰

第十二周作业

赵龙

图解图库JanusGraph系列-一文知晓“图数据“底层存储结构(JanusGraph data model)

洋仔聊编程

janusgraph 图数据库 存储结构 图解源码分析

云小课 | 一份超实用的勒索病毒自救预防指南

华为云开发者社区

勒索病毒 弱密码 云小课 企业主机安全 病毒云查杀

加密数字货币钱包APP系统开发,数字货币钱包系统定制

13530558032

首发!阿里面试官总结从零到架构面试宝典,是时候让面试官懵逼了

周老师

Java 编程 程序员 架构 面试

Android中的特殊攻击面(二)——危险的deeplink

OPPO安全

android 安全攻防 安全

打开 政务上链 应用场景

CECBC区块链专委会

区块链 数字身份 政务

LeetCode题解:155. 最小栈,使用链表代替栈,JavaScript,详细注释

Lee Chen

LeetCode 前端进阶训练营

Android 中的特殊攻击面(一)——邪恶的对话框

OPPO安全

android 安全攻防 安全

区块链技术创新应用势在必行 食品药品开启全链条溯源时代

CECBC区块链专委会

区块链 溯源 药品

Android的特殊攻击面(三)——隐蔽的call函数

OPPO安全

android 安全攻防 安全 函数

隐秘的MySQL类型转换

架构精进之路

MySQL

SpreadJS 纯前端表格控件应用案例:Teammark知识管理库

Geek_Willie

SpreadJS

架构师训练营第 0 期第 12 周作业

无名氏

不按套路出牌的阿里面试官:“刁难”面试者常用套路,你中招了吗

周老师

Java 编程 程序员 架构 面试

区块链USDT支付系统,USDT承兑支付软件开发

13530558032

架构师培训 -12 hadoop

刘敏

前端源码宝库

InfoQ_34a83d636158

为什么阿里巴巴的程序员成长速度这么快,看完他们的内部资料我明白了

Java迁哥

Git技术干货!工作中"Git"的使用实践和常用命令合集!

洋仔聊编程

git git常用命令 git常用实践 工作中git的使用

超声大数据应用

周冬辉

大数据

除了方文山,用TA你也能帮周杰伦写歌词了

华为云开发者社区

AI 数据 周杰伦 modelarts 歌词

数字货币交易系统应用开发,区块链交易所app

13530558032

交易所合约跟单系统源码开发,合约跟单平台搭建

13530558032

一文说透"静态代理"与"动态代理"

洋仔聊编程

源码分析 动态代理 静态代理

收藏!一篇教会你写90%的shell脚本!

洋仔聊编程

Shell shell脚本编写 收藏教程

【架构师训练营】第 12 周作业

花生无翼

2020中国技术力量年度榜单盛典

2020中国技术力量年度榜单盛典

十个有用的软件开发原则-InfoQ