0%

原文链接

现代应用程序很少从零开始构建。它们大多会整合市面上已存在的工具——组件、库、框架——主要有这么几个好的理由:

  • 应用程序的规模、复杂性和复杂程度都在增长,但开发它们的时间反而越来越短。所以让开发人员专注于写更多业务领域代码,少搞基础设施,可以更好地利用他们的时间和智慧。
  • 相比于一揽子开发,广泛地采用组件和框架能使bug更少。
  • 有很多免费且高质量的软件可以从网上获取,这就意味着更低的开发成本和更高的可能性找到那些符合自己兴趣和专长的开发人员。
  • 软件的生产和维护属于劳动密集型工作,所以选择购买可能要比自己开发划算得多。

无论如何,为你的应用程序选择一款趁手的工具还是相当棘手的事情,需要深思熟虑。事实上当做出选择时,需要牢记这么几件事:

  • 不同的工具可以依赖不同的情景假设——比如周围基础设施、控制模型、数据模型、通信协议等。这些都可能导致程序和工具间的架构错配。错配又会进一步让你想要破解和变通,结果写了很多完全没必要却很复杂的代码。
  • 不同的工具有不同的生命周期,当工具增加新的功能、改变设计、甚至是bug修复导致和其他工具不兼容,此时要升级它们其中之一,可能会变成一个极困难且耗时的任务。工具越多,问题也会变得越多!
  • 一些工具需要相当多的配置。通常通过一个或多个XML文件,这些文件会很快失控。最终这个程序看上去就像全部由XML加上几行奇怪的其他语言的代码写成的。这个配置的复杂度将大幅提升程序的维护和扩展难度。
  • 当代码严重依赖供应商产品到一定程度受的限于他们,可能会被供应商锁定:可维护性、性能、迭代能力、价格等。
  • 如果你打算使用免费软件,你最好搞清楚它不是真的免费。你可能需要购买商业技术支持,这可并不便宜啊。
  • 许可证条款很重要,即便是自由软件也一样。举个例子,一些公司是禁止使用任何GNU许可证发布的软件的,因为它的病毒性质——即,用它开发的软件,必须连源码一起发布。

我个人关于缓解以上问题的策略是,刚开始仅采用绝对必要的工具。通常最开始应该把重点放在为了移除那些需要从最底层的开发任务(和问题),例如,采用中间件取代原始套接字的方式开发分布式程序。然后按需增加。我更倾向于通过接口和分层的方式把外部工具和业务领域对象分离开来,所以当我要解决某些痛点时,可以选择改变工具。这种方法有个好处,我通常可以得到一个更小的应用程序,且对外部工具的使用也比原先少。

原文链接

开发者——至我们所有人!是否经常焦虑自己的代码被否定。不存在的,就算有,也肯定是编译器的错。

而实际情况是一段代码出错几乎(一万个几乎)不可能是由于编译器、解释器、OS、应用服务、数据库、内存管理器,或任何系统级的软件导致的。你信或者不信,bug就在那里,只是没你想的那么普遍。

我有次是真遇到这种情况,编译器错误地优化了循环变量,但在此之前我已经在脑瓜里意淫过无数遍(就是编译器的错)。我浪费了大把的时间,都把时间花在意淫里,然而事后证明就是自己的错时,又感觉自己多么愚昧。

假设一个工具被广泛使用,且成熟应用于各技术栈当中,那只可能有很少的情况下应该去质疑它的质量。当然,除非它刚发布,或者用的人很少,再或者下载量小,0.1版本,开源软件等情况下,确实有可能找到很多质疑点。(同样,商业软件的alpha版本也会被质疑)。

编译器级别的bug如此罕见,你其实可以更好地花时间和精力去找到错误,而不仅仅是为了证明是编译器的错。利用所有可用的调试手段,隔离问题,存根调用,包围式打击(测试);检查所有调用约定、共享库、版本号;和别人解释;找出堆栈破损以及变量类型不匹配的地方;尝试在不同机器及不同构建配置中重新跑这段代码,比如debug和release版本;

质疑你自己的假设和他人的假设。工具出自不同厂商之手,就会有不同的情景假设来构建它们——同一个厂商的不同工具也可能。当其他人在报告这个问题你就没必要重复了,去看看他们在做什么。他们可能正在做一些你从未想过或不按套路走的事情。

如果有bug却无法定位问题的时候,个人往往会认为问题出在编译器,并把时间用来查找堆栈破损。如果经过跟踪调试后解决了该问题,那就确定无疑了。

其他代码中的bug引发的多线程问题可以把你头发都急白了。所有建议都赞同,简单的代码在多线程系统里将变得不简单。调试和单元测试在查找一致性错误时会变得不可靠,所以请保持简单朴素的设计。

所以,先别急着去怪编译器,记住夏洛克·福尔摩斯的一句话:“排除一切不合理,无论剩下什么,无论多么不可能,那就是真相”。更喜欢Dirk Gently的另一句话:“排除一切的不可能,无论剩下什么,无论多么不合理,那就是真相”。

如果文章是写给别人看的,就请停止自嗨!

我们都是巨婴

曾几何时,“巨婴”一词冒了出来,专指那些永远长不大的成年人。任何事都要及时满足,没了就情绪暴躁,只要自己开心,负天下又何妨?

我们又可想过自己也是个巨婴,不能没有Wi-Fi,眼里只有手机屏幕,文章长一点就看不下去。说到底,对这个世界越来越没耐心了

自媒体时代,很多人的自我表现欲望被激发出来,通过自媒体平台,我们可以提升人脉圈,塑造个人品牌,甚至财务自由。而如果你没有靠脸吃饭的命,想要靠才华,入门级的方式就是——写作

阅读全文 »

原文链接

童子军里有条规矩:把你离开的营地打扫的比刚来时还要干净!如果你发现一块脏乱的地方,别抱怨谁弄的,把它清理干净。为了下次来访的野营者们你要刻意改善这里的环境。其实这出自侦察之父Robert Stephenson Smyth Baden-Powell(罗伯特·史蒂芬斯·史密斯·巴登-鲍威尔):“试着把这个世界变得比你发现它时更好一点”。

如何我们在代码世界也遵循类似的规则:签入一个模块时总是比签出的时候更干净。不管上次的代码时谁提交的,如果我们总能努力改善一些东西,哪怕只有一点点。结果会如何?

我认为如果我们都能遵循这个简单的规则,我们会看到软件系统不断恶化的情况将得到制止。同时,我们的系统将朝着越来越好的方向发展。我们也能看到团队更加在意系统的整体性,而不仅仅是他们个人负责的那一小块。

我不认为这个规则太长以至于要问的太多。你不需要把所有模块都做到完美在签入库中。你只需要做得比刚签出时好那么一点点。当然,这也意味着你添加到模块中的代码都必须保持干净。也就是说你必须整理至少一个地方再签回去。可能是完善一次变量名,又或者把一个冗长的函数切成两个小函数。你可能跳出了死循环,或者增加一个接口把策略从细节中剥离出来。

老实说,这个观点对我而言很普通——就好比上完厕所要洗手,或把垃圾丢到桶里而不是地上。确实,丢下一对脏乱差的代码走掉,从社交层面看也不可取。这会被视作工作未完成。

其实不止于此,关注自己的代码是一回事,关注团队其他人的代码是另一回事。团队互相帮助,互相彼此整理。遵循童子军法则,会让每个人受益,而不仅仅是个人。

不论过去未来还是现在,人类一直都活在故事当中。

忽然想到一段相声:

1
2
3
郭德纲:你有《时间简史》吗?
于谦:我有时间也不会去捡屎!
😂😂😂

先看看《今日简史》的英文书名《21 Lessons For The 21st Century》——《21世纪21堂课》,所以简史三部曲的最后一部并没有去捡“史”,我估计取这么个中文名纯粹是为了商业营销。而赫拉利在本书中,确实围绕当下全球的几大热门主题和细分领域做了谈了自己的见解和价值观。与前两本简史相比,本书没什么脑洞,甚至没有明确的主线,但同样发人深省。

阅读全文 »

那是我到公司的第一个项目。我刚毕业一心想要证明自己,每天都调代码到很晚。当我每get到一个新特性时,都很认真地把学到的东西——尽可能注释、日志、推送到代码共享库中,就这样工作着。但对我认为很OK的代码审查却让我醍醐灌顶——重用得不好。

为什么会这样?整个大学的复用被认为是高质量软件工程的缩影。我读了所有的条款,书籍,接受过非常有经验的软件专家的教育。这些全是错的?

事实证明我确实错过了一些关键事情。

上下文

系统中两处有复用接口的地方实际执行相同逻辑情况比我想象中少。就算我把代码从库里再拉取一遍,这些部分也没有其他依赖。彼此独立推进,独立修改逻辑以适应系统业务需求的改变。有四行相似的代码出问题了——时间异常、耦合。直到我继续深究。

我创建的这个代码共享库就像把鞋带相互绑在每只脚上。创建一个业务领域之前必须先与另一个进行同步。这样独立的功能维护成本可以忽略不计,但公共库则需要巨量的测试。

当我想要减少一定数量的代码行数时,我却要增加同等数量的依赖。这些依赖对上下文必须非常严谨——确保被分配过,有正确合理的赋值。当这些依赖得不到检查时,即便代码看上去没问题,整个系统也会被它们绕死。

这些错误就潜伏在那,当然从核心来看貌似是不错的想法。当调用它们的上下文正确时,这些技术会很有价值。但当上下文本身不好时,它们给系统带来的负担已经超过其价值。当入库的代码存在大量不懂技术的复用时,我都会在最近几天非常留意这次分享。

小心分享。检查你的上下文。确保OK,再继续。

原文链接

有时候程序员需要对现有代码重构。但在此之前你要思考以下几点,这能帮你和他人省去大量处理时间(和痛苦):

  • 重组的最佳方法始于现有代码库的评估及测试。这能够帮你理解当前代码中好和烂的部分,你就能取其精华去其糟粕。我们都认为自己可以做的比现在的系统更好…然后我们交付的东西可能不咋地,甚至更垃圾,因为我们没有从以前系统的缺陷中总结教训。
  • 要禁得住推翻重来的诱惑。最大程度地重用现有代码。不论这些代码写得多丑,毕竟它通过了测试和审查等。抛弃旧的代码,尤其是已投入生产使用的,就意味着你正在抛弃历经一个月(或一年)的测试和身经百战的代码,但其中有某些变通和修复bug的方法,只是你不知道而已。如果你不考虑这一点,你写的新代码可能会重现已被旧代码修复过的bug。它们会占用你大量的时间、精力和多年的知识积累。
  • 大量的小改(增量修改)要比一次性大改好太多了。增量修改允许你通过反馈轻松地衡量对系统的影响,例如单元测试。谁也不想一次看到几百个测试失败的情况吧。那会因为压力和挫败感进一步导致错误的决策。一两个测试失败却很好处理,而且会有更多选择方案。
  • 每次迭代后,已通过的现有测试将成为重要的保障。当现有测试不能完全覆盖代码变更时就添加新测试。千万不要不经大脑直接从旧代码中移除测试。表面上看这些就测试已无法适应你的新设计,但为什么要加入此测试的原因是非常值得深入研究的。
  • 个人偏好和自我不应该在重构的时候出现。如果一些地方没出问题,你干嘛要修复它呢?代码的风格和架构都不应该有你的个人偏好,更不该是重构的理由。自以为你可以做得比之前的程序更好,也不该是重构的理由。
  • 新技术也不足以成为重构的理由。现有代码所使用的技术已经落后于当今是最糟糕的重构理由之一,之二便是我们认为新语言和框架可以更优雅地解决这些事。除非成本收益分析显示新的语言或框架可以让功能性、可维护性以及生产力得到显著改善,否则最好保持原样。
  • 永远记住人是会犯错的。重构不可能保证每次都更比以前的代码好甚至完美。我也曾看到并参与几次重构失败的情况。它不完美,因为这是人类的功劳。

在苍蝇眼里,屎有美感吗?

也许正如书中所说,本书的观点更多的仅是表达对未来人类发展进程的一种可能性,只是一种观点,不是预言。也许是我对《未来简史》中的“未来”二字期望太高,但我可以肯定的是书中2/3的篇幅都在讨论现在和过去人类的意义,而非畅想未来。总体而言,不如《人类简史》读起来酣畅淋漓。但确实也有发人省醒的地方。

阅读全文 »

原文链接

我认为所有程序员都应该铭记一句话:

风格和谐优雅有韵律的美,源自简单 ——柏拉图

对于这句话,我认为这是所有程序员都应该追求的价值观。

下面这几天是我们在写代码时应该居于力争的:

  • 可读性
  • 可维护性
  • 开发速度
  • 美好的气质

柏拉图告诉我们要达成这些品质,都需要简单。

什么是美的代码?这是一个非常主观的问题。美的认知很大程度上取决于个人的背景,因为我们对任何事物的认知都取决于我们的背景。一个被艺术熏陶的人对美的认识(至少是感觉上的接近)肯定和一个接受科学教育的人有所不同。关于软件的艺术,艺术专业的人倾向于把软件与艺术品比较来感觉其中的美,但科学专业的人会说关于对称性和黄金比例的话题,尝试着把它简化为公式。根据我的经验,简单性就是双方多数论点的基础。

想下你研究过的代码。如果你不肯花时间看别人的代码,立刻关闭这篇文章,然后去找一些开源的项目来学习。我是说真的!搜点你常用语言做的web开源项目,最好是那些著名的、公认的专家写的。

(假装离开了好久…)哥们儿回来啦?灰常好,我刚说到哪儿了?啊—yeah…我发现能和我产生共鸣或我觉得很漂亮的代码都有很多共性。首当其冲就是简单。我发现一个app或系统不论多么复杂,其各个部分都必须保持简单。具备单一职责的简单对象都包含简单、高内聚的方法。有些人觉得一个方法只有5到10行代码是在搞笑,很多语言根本不可能做到这一点,但我觉得梦想还是要有的。

简单的代码就是美的代码,这也是底线。各个部分都应保持简单单一职责,且和系统其他部分耦合度低。社会主义信息化建设可持续维护道路:干净、简单、可测试代码、飞一般的开发节奏,贯穿系统整个生命周期。

美,源自简约

原文链接

你可能也感同身受。在项目刚开始时,每个人都对项目有很多提议——叫做“新项目决议”。经常,这些决议会被写进文档。让代码符合项目的代码标准。在项目启动会议时,开发主管会通过这些文档,在理想情况下,每个人都同意遵循这套规则。一旦项目开始,这些好的建议会被一个又一个地抛弃。到项目收尾时,这些代码将混乱不堪,而且居然没人知道是怎么成这样的。

什么时候开始出错的?可能在项目启动会议就开始了。一些项目成员没有注意到,其他人可能也不理解。但糟糕的是,一些反对声和已经纳入计划的代码标准有冲突。最终,一些人可能发现了问题所在,但项目压力太大的时候,又不得不让事情继续向前推。良好的代码格式化并不能让需要更多功能的用户为你点赞。而且,如果无法自动完成的代码格式化真的很让人反感。仅能自己手动去缩进那些混乱的class。

但如果这是个问题,为什么我们刚开始就要确定一套代码标准?原因之一是格式化成统一风格后没人可以用自己的风格去“占有”一段代码。我们想要阻止开发人员使用明某些反模式,为了避免一些常规性的bug。在所有情况下,一套代码标准应该在整个项目中更容易被执行,以便从头至尾维持开发速度。接着,每个人都应该同意这套风格——如果有人用三个空格缩进,有人却用四个,那这风格就完全没意义了。

有大量的工具可以用来生成代码质量报告以及文档,以维持代码标准,但这不是全部解决方案。它应该尽可能被自动和强制执行。比如以下:

  • 确保代码格式化属于工程建立的一部分,这样每个人在编译自己的代码事会被自动格式化。
  • 使用静态分析工具去扫描代码是否有反模式,一旦发现,中断构建。
  • 学习配置这些工具以便你能扫描自己代码,特定项目的反模式。
  • 不仅要测量测试覆盖率,还要自动检查这些结果。再有,如果测试覆盖率太低也要中断构建。

尝试去把你认为重要的任何事做到这一点。你不能让每件你关心事都自动化。对于这些无法自动标记或修复的事情,考虑为它们制定一套补充指南,以确保代码标准能被自动化,但你和你的同事们未必会遵循它。

最后,代码标准应该是动态的而非静态的,随着项目的发展,它需要随项目改变,因为刚开始看起来英明的事情,过几个月可能就没那么英明了。