阅读更多

1顶
0踩

研发管理
有时候我们说,“实现这个功能,我只花了几个小时”。但是完成之后,我们发现每隔几周,我们要么在修复该功能的bug、向另一个工程师解释,要么做客服回答问题、以解释其工作原理。维护该功能总的投入时间要远远超过最初开发的几个小时。

软件开发中内化的最艰难教训之一就是额外复杂度所带来的隐形成本。有时候,复杂度在问题领域只是固有的。为了匹配乘客和司机,通过调整价格来平衡供求是一个复杂和痛苦的问题。因此,在扩大一个社区和维护社区质量的时候,把问题和答案疏通到喜欢回答和看问题的人们那里,也是如此。或者像是开发一个兼容所有设备的富文档编辑器以支持实时协作。这是固有的复杂度,我们需要根据产品做出调整以取得成功。

但是其它时候,和我们较劲的复杂度恰恰是我们自己产生的复杂度。我们用新编程语言写代码,很少人了解它,现在我们不得不维护它。或者我们增加了额外的基础架构,因为我们尝试从Hacker News看到的、热门新技术,但是它失败了,这是我们当初没有想到的。或者我们引入了一个很少人使用的功能,但是修复和bug报告就花掉了极不对称的大把时间。

额外的复杂度暴露了很多隐形成本。在开发软件时,我们所做的决定不只是决定了我们当前的开发速度。它们还要反映出我们花在维护上的时间和努力程度。

复杂度的隐形成本

太多复杂度增加了认知负荷,并产生了做完事情的额外阻力。它以很多不同的方式渗入到团队里——大部分是直接渗入到代码、系统和产品复杂度里,但是间接地渗入到了组织的复杂度里。我们逐个看看这几种不同类型复杂度的隐形成本。

代码复杂度

代码复杂度不只是随着代码行数的线性函数而增长——它组合式地增长。在复杂的代码库里,每行代码可能与其它很多行代码交互和影响。我们对于组合式增长难以有足够的认识,这就是为什么我们倾向于严重低估完成大型软件项目所需要的时间。这也是重写项目有时候会大幅延期的主要原因。

当代码过于复杂的时候,它将变得难以扩展、难以理清其中缘由、难以修复bug,很难理清追踪错误来源的依赖和数据流向。工程师或许会积极地避免代码库最复杂的部分,即使它是可以做某种修改的、最有逻辑的地方,也要选择绕弯来解决。他们或许避免把那些地方都组合起来,即使这项工作有着很大的影响。

系统复杂度

工程师喜欢摆弄新玩具,要么因为好奇,要么因为他们认为新技术可能为解决他们的紧迫问题提供了银弹。当Pinterest在2011年刚开始扩容网站以应对快速增长时,他们只有3个工程师的后端小组却使用了6种不同的存储技术(MySQL、Cassandra、Membase、Memcache、Redis和MongoDB)。他们实验每项新技术的诺言都是解决现有系统的某些限制。但是,每种新解决方案都以其自身特定方式失败了,为了管理和维护而投入了更多时间和努力。最终,团队明白了,增加更多机器而不是更多技术,更能简化扩容,因此他们消除了Cassandra和MongoDB之类的系统,强化了架构的已有组件。

把基础架构切分为太多系统,会带来很多隐形成本。注意力被分散到了多个系统。对于每个系统来说,更难以整合资源以开发可复用的资源库,更难以为日常工作招聘新人,更难以理解具体的失败模式和每个系统的性能特点。每个系统的抽象最终变得更弱,因为没有可投入的太多时间。当工具和抽象太复杂、或太多的时候,让团队去理解和探索将变得困难。

产品复杂度

产品复杂度可以导致一个不明确的版本、或引发缺乏产品聚焦的无节制野心。它希望在很多地方是优秀的,而不只是在一个核心领域,这种欲望使其不能向新用户明确地解释产品的意图。产品复杂度引发了更多的代码和系统复杂度——团队增加更多代码、更多基础架构以支持新功能。当产品外围宽泛时,增加一个新功能或修改现有功能,将需要放大很多的努力来理解和适应旧的功能。

过于复杂的产品意味着有更多的代码分支,更多要考虑的问题、更多的需要团队解决的bug反馈。工程师和数据科学家需要分析更多的变量、做更多的一次性的报表,而不是集中于核心用户行为的理解上。工程师需要投入更多时间来提供功能空间和提高效率。每个人最终在更多的项目中进行切换。投入在维护所有这些功能上的时间,并不是重新投入代码、偿还技术债务、加固抽象的时间。

组织的复杂度

代码、系统和产品复杂度,依次产生了组织的复杂度。团队需要雇佣更多人来处理和维护已开发的所有东西。越大的团队意味着越多的沟通成本、越多的协调和和越低的总体效率。招聘过程本身,涉及的所有面试和汇报,消耗了团队很大比例的时间。当然,所有新员工不得不被培训才能上岗。

雇佣更多人的替代方法,就是将工程师组成划分成更小的团队——或许甚至创建了一人小组——来承担较多代码、系统和产品外围的工作。这降低了沟通成本,但是一人小组有他们自己的成本。一旦遇到难题,就完全拖延了项目中的唯一人手,因为有更少的人来分享这些低谷期,这种体验对于士气是有害的。与其他人合作的机会少了,会伤害到工作场所的快乐和员工的留任。除非每个人比较自觉,而且主动询问反馈,否则个人收到的工作反馈将更少,因为分享相同项目上下文的人更少了。减少的反馈能够降低代码质量、或因疏忽导致的复杂度引入到代码库或基础架构里。

如何应付复杂度

Tony Hoare在1980年图灵奖的演讲中建议,“构造软件设计有两种方法:一种是简单,明显地没有缺陷;另一种方法是使其复杂,却没有明显的缺陷。”提到了由于复杂度而导致的非明显的缺陷是如何伤害我们的,以及我们该如何应对这些成本?

下面是你能够用到的一些策略:

  • 为简单而优化。抵制增加更多复杂的主张。深思维护成本。要自问,为了解决20%的问题而引入的复杂是否值得,或者80%的解决方案已经足够了。
  • 为你的团队或产品定义一种任务说明以统一思想。在Team Geek,Brian W. Fitzpatric和Ben Collins-Sussman解释了他们是如何辅导Google Web Toolkit(GWT)团队、并鼓励他们写下任务说明的。接下来发生的、对于任务说明的内容和形式的争论,表明了首席工程师并不真正认同产品方向!他们被迫面对、协调不同、并最终达成了,“GWT的任务是为用户彻底提升web体验,让开发者使用现有的Java工具在任意现代浏览器里构建高性能的AJAX。”如果他们不能尽早找出这些区别,随之而来的努力上的分散又有多少呢?
  • 用较小的构建块组成大型系统。Google就是个例子,致力于构建健壮的核心抽象,然后被非常宽泛的应用程序广为使用。他们有基础的构建块,像Protocol Buffers、Google File System和远程程序调用的Stubby服务器。基于这些构建块之上,他们还建立了其它抽象,比如MapReduce和BigTable。在此之上,包括大型web索引、Google Analytics站点追踪、Google News聚合、Google Earth数据处理、Google Zeitgeist数据分析在内的数以千计的应用程序,还有很多程序都是这样构建的。
  • 清晰地定义模块和服务之间的接口。模块和服务的退耦,将减少能够产生一堆代码的组合复杂度。在Amazon,Jeff Bezos于2002年宣称,公司将转向面向服务的架构,所有团队只能通过服务层级的接口彼此交流。虽然这个转变造成了本身巨大的开发成本,但是它强制分离了代码和服务背后的逻辑,为现在极度成功的Amazon Web Services的建立提供了便利。
  • 优先偿还技术债务。我们总是在信息不完全的条件下开发软件。做为条件变化的响应,代码库在增大,熵也在增大。增加的复杂度成为了未来开发的代价。在开发日常上预算时间可以减少这项成本。很多工程师和团队在项目之间预算这项时间,不过召开一次性的会议会有帮助。我过去在Quora组织过一次Code Purge Day(代码消除日)活动,工程师在这一天全部关注删除无用代码的工作。我们在积分牌上追踪代码消除的进度,这使得删除你自己的代码更有趣味。
  • 使用数据修剪没用的功能。在Yammer,当工程师或产品经理发现在代码重构时,强化或保留一个功能将花费不菲的时间时,他们将查看使用数据,以确定这项功能是否真正被使用了。如果没有,他们将和团队一起决定,他们是否应该只是砍掉这个功能以降低总体工作量。与简化的代码是怎样减少技术债务一样,这个策略也减少了技术债务。
  • 基于主题对进行中的项目分组。使同事彼此分享同样的环境,更容易地参与到设计讨论、代码评审或构建可复用的资源库。所有这些活动有助于提供检查和平衡掉单个人或其他人所引发的问题。
当我们为学校课程开发软件时,我们有着世界的过于简单的视角——维护任意复杂度的成本随着下课而消失了。但是在我们的职业生涯中,糟糕的软件决定将产生数年负担的影响。

不要使事情复杂化。

原文地址(source):http://www.theeffectiveengineer.com/blog/hidden-costs-that-engineers-ignore
来自: 腊八粥
1
0
评论 共 2 条 请登录后发表评论
2 楼 ttt725 2016-02-02 17:57
       
1 楼 spiniper 2015-01-05 14:40
很精辟文章

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • [转]工程师忽略的隐形成本

    我们逐个看看这几种不同类型复杂度的隐形成本。 代码复杂度 代码复杂度不只是随着代码行数的线性函数而增长——它组合式地增长。在复杂的代码库里,每行代码可能与其它很多行代码交互和影响。我们对于组合式...

  • 美好的十年工程师生涯

    他们抗风险的能力差,有一主要原因,就是设计,生产成本过高,而有着巨大市场的中国会慢慢的由制造中心 的角色转化为设计中心,研发中心。大批的外方研发人员和核心技术的研发将陆续转移到中国,在这种大背景下,...

  • 一个产品想要成功,产品经理必须要有成本意识

    产品的出发点是为了解决用户的痛点需求,其目的是为了给用户创造利益(价值),所以,但凡涉及到这个产品的相关方,开口闭口都能是场景、体验这些高级词汇,但在另外一端容易被忽视,那就是成本问题。如果你只是盯着...

  • Google 最高级别工程师的教育梦

    Udacity 上的课程有免费课程也有收费课程,由于 Google、Facebook 这些工程师的薪资很高,所以设计的课程人工成本较高,所以,不少同学反馈 Udacity 上的收费课程有点贵,这不,马上双 11 了,什么都打折,一年一次...

  • 美好的十年工程师生涯(转载)

    他们抗风险的能力差,有一主要原因,就是设计,生产成本过高,而有着巨大市场的中国会慢慢的由制造中心 的角色转化为设计中心,研发中心。大批的外方研发人员和核心技术的研发将陆续转移到中国,在这种大背景下,...

  • 测试开发工程师常见面试题

    以下不作为测试工程师的学习路径,只是汇总的校招测试工程师面试考点(因为还有笔试考点,后面结合在一起给大家学习路径),后续会为大家更新10w+字数的测试工程师校招面试题库,还有其他岗位的相关题库和资料,想要...

  • 测试工程师,跳槽涨了4k,年总包算下来还降薪了?

    所以,除了薪资福利外,还得把这些隐形资产也都算在里面。 接下来聊聊如何谈薪资。 第一,先计算清楚当前的薪资总包,包括基础薪资、五险一金、年终奖、项目奖、福利待遇以及其他。 再结合你的背景经验和目标岗位的...

  • 十年工程师生涯总结

    他们抗风险的能力差,有一主要原因,就是设计,生产成本过高,而有着巨大市场的中国会慢慢的由制造中心 的角色转化为设计中心,研发中心。大批的外方研发人员和核心技术的研发将陆续转移到中国,在这种大背景下,...

  • 前端开发工程师面试题2

    前端开发工程师面试题2    1、Doctype作用? 严格模式与混杂模式如何区分?它们有何意义?  (1)、 声明位于文档中的最前面,处于 标签之前。告知浏览器的解析器,用什么文档类型 规范来解析这个文档。  (2...

  • 导致嵌入式系统项目失败的7个隐形杀手

    对工程师而言,没有什么事情比投入大量心力、汗水和泪水到一个项目,但最终却只得到一个失败的结果这件事,来得令人沮丧。对那些参与项目开发的人来说,失败确实可以增长其洞察力和经验,但所时间和心力的损失却也是...

  • 美好的工程师十年

    如何看待工程师的头衔,我小时候很是向往工 程师的称呼,其实,狭义上的工程师是件很简单的事,本科毕业的第三个年头,就可以参加参加职称考试获得一纸证书 就算是工程师啦,同事或供应商叫你X工,好像也有了几分...

  • 项目管理1:嵌入式系统项目失败的7个隐形杀手

    #5 - 完美主义者的态度 许多工程师都有一种完美主义者的态度。这种态度所带来的问题是,不可能开发出完美的系统,撰写出完美的代码,或者在最适当的时间推出产品。完美主义是镜花水月,如果完美主义是公司文化的一...

  • python入门-30.寻找列表中只出现一次的数字-寻找单身狗.py

    python入门-30.寻找列表中只出现一次的数字——寻找单身狗.py

  • 布尔教育linux优化笔记

    linux优化笔记,配套视频:https://www.bilibili.com/list/474327672?sid=4496133&spm_id_from=333.999.0.0&desc=1

  • 知识付费系统-直播+讲师入驻+课程售卖+商城系统-v2.1.9版本搭建以及资源分享下载

    知识付费系统-直播+讲师入驻+课程售卖+商城系统-v2.1.9版本搭建以及资源分享下载,CRMEB知识付费分销与直播营销系统是由西安众邦科技自主开发的一款在线教育平台,该系统不仅拥有独立的知识产权,还采用了先进的ThinkPhp5.0框架和Vue前端技术栈,集成了在线直播教学及课程分销等多种功能,旨在为用户提供全方位的学习体验,默认解压密码youyacaocom

  • 美妆神域-JAVA-基于springBoot美妆神域设计与实现

    美妆神域-JAVA-基于springBoot美妆神域设计与实现

  • 原生js制作Google粘土logo动画涂鸦代码.zip

    原生js制作Google粘土logo动画涂鸦代码.zip

  • golin 扫描工具使用, 检查系统漏洞、web程序漏洞

    golin 扫描工具使用, 检查系统漏洞、web程序漏洞

  • 原生态纯js图片网格鼠标悬停放大显示特效代码下载.zip

    原生态纯js图片网格鼠标悬停放大显示特效代码下载.zip

Global site tag (gtag.js) - Google Analytics