Some thoughts about software design.

“Do one thing every day that scares you.” -- Eleanor Roosevelt

Posted by Nickolas on September 9, 2018

导言

刚刚接触开发的时候, 总觉得软件设计的思想通常都是大而空的, 泛泛而谈, 没什么实用价值. 随着自身经验的积累, 不断回顾自己做的设计和选择, 观察身边同事的软件设计方法论, 慢慢意识到软件设计思想的重要性. 这方面的思考虽然不像特定的技术一样能够解决某个领域的问题, 但当一个软件产品不只停留在可用阶段, 而是要长期迭代, 发展, 维护时, 软件设计的思想就变得很重要. 软件规模越大, 生命周期越长, 设计的方法越重要.

这里并不是想说设计模式那些具体的方法, 而是想从自身的经验出发, 反思自己做过的好的不好的选择, 总结自己软件设计的一些方法论. 这些方法不会适用于所有的问题, 但重要的是保持这种思考的习惯, 并形成自己的一套经验体系.

架构设计–避免过早优化, 避免过度设计

软件产品的一个特点是变化, 业务产品要适应不断变化的市场, 技术产品要适应新的技术环境和不断扩展的技术人员的认知. 面对未来的变化, 很容易拖累技术人员的是未来可能的功能, 未来可能的市场规模, 未来可能的性能瓶颈. 产品的未来是很难预估的, 那些未来的功能不仅可能没有, 还会成为现实的拖累.

早些年做的一个系统, 基于面向对象的思想和单一职责原则, 把功能拆的特别细. 这样虽然新加的功能可以在对象体系中新建新的类来完善整个系统, 但是面向对象, 尤其是对象的继承体系的缺点是一旦结构设计出来了就很难被变动, 调整一个对象继承体系是异常困难的. 这样就需要开发人员事先能够很清楚软件的未来走势, 否则慢慢这个体系就会变得很别扭, 过去的设计慢慢成为现实的拖累.

既然未来是不断变化并且很难预测的, 最好的方法是保持设计和现有功能的简单. 尤其是早期的产品, 架构的设计要尽可能简单, 根据产品的定位保留扩展的能力. 同时要抵制住未来功能的诱惑, 未来功能可以先规划好, 到时再实现也不迟. 未来架构的设计可以很复杂, 心中保持着对未来的无限想象, 但是具体的实现一定要尽可能的简单, 代码上少即是多.

在功能开发上少即是多, 性能优化同样如此. 一般的优化都会增加软件设计的复杂度. 过早的优化常常会带来过度的设计. 做任何性能优化前一定要先度量, 尽量从全局上面分析和度量, 找到性能的瓶颈之后再开始优化. 局部的优化很可能在全局来看收益并不大, 而在高一个层次思考往往可以达到事半功倍的效果.

延伸阅读可以参考Stop Future Proofing Software.

模块设计–降低认知成本

做产品UI设计, 要把用户当做小白, 能设计成点击一次的交互就不要用两次. 模块设计也是如此, 要站在使用者的角度上, 降低使用者的认知成本. 好的设计不需要大量的说明文档, 模块名, 接口名就是最好的文档, 不需要看内部的实现就能够很好的使用. 比如Java中常用的容器ArrayList就设计了很好的接口, add addAll remove removeAll get indexOf几个增删查接口清晰的定义了一个列表的功能. 再比如 SQL 查询语言, 能够用类似口语化的语句描述做什么, 而不是怎么做来完成数据的操作, 这给使用者足够多的抽象, 并给执行引擎内部留有很多优化的空间. 多年来 SQL的执行引擎越来越强大, 像InnoDB支持高性能索引, 事务, 加密, 缓存等能力, 而对外暴露的SQL 查询语言仍旧可以保持稳定.

相反的, 不好的函数和模块设计可能带有各种 side effect, 或者需要阅读大量的使用文档才能小心翼翼的使用.

总之, 小到一个函数, 一个借口, 大到一个模块, 要尽可能站在使用者的角度, 降低使用的认知成本, 把自己的实现做的越透明越好.

产品设计–产品发展阶段的思考, 关注重点

无论是业务产品还是技术产品, 他的发展都是有周期性的3. 而每个阶段所需要解决的关键问题不一样. 因此, 要认清产品所在的阶段, 解决关键的问题.

product lifecycle

在产品刚未完全被市场认可时, 这个阶段要解决产品的生存问题, 产品的方向是否能解决用户的需求. 技术产品也是一样, 没有一定用户的技术产品很快会消亡. 因此这个阶段抓住种子用户很关键, 需要持续的接收种子用户的输入, 做出真正能解决实际问题的产品.

当产品得到了市场的认可, 开始快速的规模化发展, 这个团队的资源会很快地被各种需求消耗掉, 很容易陷入到需求的恶性循环里面, 没有自己的思考, 只是满足用户的需要. 这个阶段需要对产品有自己的判断, 什么样的事情不该做, 抓住头部的用户, 同时思考如何做价值的放大, 以及通过沉淀能力等手段降低边际成本.

到了成熟期或者平台期, 之前的红利已经吃完, 重点变成了如何寻找产品的增量点, 扩展产品的价值, 或者如何扩展用户的领域, 增大服务用户的范围. 比如目前我在做的端上机器学习产品, 除了发挥端上实时性更强的优势, 能否扩展产品的价值, 能否产出更多更准确的样本, 能否保护用户的隐私. 目前的目标用户是算法工程师, 能否将用户扩展到普通的业务工程师, 让后台和客户端工程师也能开发端上机器学习任务. 产品的增长点又是一轮从初创期到增长期, 再到平台期的一个过程.

延伸阅读

1: https://medium.com/@george3d6/stop-future-proofing-software-c984cbd65e78 2: https://dev.mysql.com/doc/refman/5.6/en/innodb-introduction.html 3: https://www.tutor2u.net/business/reference/product-life-cycle