分享 你是 “最佳实践” 的受害者吗

lanzhiheng · 2019年01月28日 · 最后由 EvanYa 回复于 2019年02月11日 · 3155 次阅读
本帖已被设为精华帖!

关于最佳实践的一些碎碎念,言辞有点激烈,可能会因此得罪一些人。


Hacker

这篇文章是有感而发,也算是自己软件开发生涯的一些所思所想的总结吧。IT科技在这几十年来发展迅速,各个领域都萌生出所谓的“最佳实践”。今天主要想来谈谈这些所谓的最佳实践可能并不是那么的“最佳”,甚至有的时候它们还会是“最糟”的存在。

表明立场

首先需要表明一个立场,我并没有排斥最佳实践的意思,我跟许多人一样是Ruby On Rails,Django这些Web开发最佳实践的全栈式框架的受益者。这些框架的开发者根据自己或者社区的经验把一些能够方便开发者的,比如,数据库操作,目录结构,路由定制等特性进行有效组织并集成到框架当中,虽说不同的社区侧重点有所不同,但是总体而言并没有脱离MVC这个基础模型。或许我可以认为即便它们“长相”各异,写法各异,分属于不同的社区,但他们的核心灵魂以及概念是想通的。

然而如果要脱离基础概念,区别对待,硬要从Rails,Django这些框架中选择出一个所谓的“最佳实践”就有点耍流氓了。前面也说过每个社区的侧重点不同,我以前写Django的时候还不知道有静态资源编译这回事,那时候的Rails早就有了AssetsPipline。另外,Django可能是为了让i18n的性能更加出众,相关的翻译资源都需要经过预编译的,而Rails则是运行时直接从yml文件中读取。那到底谁的做法更佳?似乎是个见仁见智的问题了。

为此请允许我简单把最佳实践归纳为

特定领域最佳思想之实践。

跟今天许多人所寻求的“最佳框架”,“最佳语法”的实践似乎不是同一个频道。你会以运行速度不够快来抨击Ruby,他会以啰嗦来抨击Java,还有人会以语法过于复杂来抨击C++。在这种层面上谁才是“最佳”真的能够争出个结果来?合适的才是最佳的。

下面我从几个方面来谈最佳实践,以及一些最佳实践为团队带来的负面影响。

最短即“最佳”?语法糖的滥用

今日之开发,抽象程度越来越高了。人们之间似乎流行出一种“最短”即“最佳”的想法。

想想刚入前端圈那一年工作组为了“掩盖”语言本身的“丑陋”,发布了ES6,确实带来了许多好处,比如总算有块级作用域了,class关键字也能用了,生成器,装饰器都有了。有了这些利器我们可以让代码变得更简短,优雅,这本身并没有什么问题,但是这似乎也为过度封装大开方便之门。

拿装饰器来说事,它实质上就是一层语法糖衣,它的作用大概如下

@decorator
class A {}

// 等同于

class A {}
A = decorator(A) || A;

这是一个不错的改善,能够精简语法。但是一旦被过用,代码将会变得有点奇怪了,我曾经见过这种代码

@a
@b
@c
class A {}

好好的糖衣变成了糖精-或者说语法糖浆(英语:syntactic syrup),指的是未能让编程更加方便的附加语法。这似乎应了那句话

金钱使浅薄的人更浅薄,使深刻的人更深刻。

最早接触装饰器是写Python的时候,我记得当时有个人说过:“即便装饰器很好,但是如果多了它会使代码变得晦涩难懂,所以请尽量限制层数”。作为程序员应该要在代码易读的基础上让代码变得更简洁,脱离易读性而单单追求简短的代码纯粹是炫技,如果真的只是为了炫技而写代码,何不直接写二进制?那就真的没几个人能看懂了,而且还会显得自己很高端。

统一写法等同于最佳实践?

最近许多人都追求写法统一

Write Once Run Everywhere

美其名曰提高开发效率,能够使得程序员更高产。React Native这些技术的出现,让JavaScript编写移动端应用成为可能,这似乎是好事,我可以只学会React技术就去编写移动端软件了。更有甚者MPVUE以及Taro等框架的兴起,似乎意味着只需要学React或者Vue就能够编写各种小程序或者APP了。假设你有一个React的团队,或许采用Taro这些框架将会比写原生的小程序原生语法更爽,许多人把这看成是最佳实践。不过据我观察,世界比你想象的要残酷。

毕竟我没能够开发出这种类型的框架,没资格对这些框架评头论足,但我只想就事论事。关于统一写法我有以下的考虑

1. 统一写法重要吗?

我记得有一些这类框架的拥戴者的说法是“微信的语法很多坑,所以我要上这个框架。”,“应该把注意力放在用React或者Vue来写特定业务,而不是小程序的坑爹语法。”等等。

对这些说法我觉得用Erlang语言的发明者Joe大大的话来回答最好

Erlang并不适合处理所有场景,如果你发现有其他语言更适合某种场景,我将会是第一个支持你使用别的语言来解决这个问题的人。

每门技术都有它擅长的事情,什么都想干,最终可能会导致啥都干不好。即便工作组不断在“优化”JavaScript语法,JavaScript也不可能一统天下。统一写法并不是银弹,能够用Vue和React语法来写小程序似乎是一件令人开心的事情,但回过头来想,学习小程序难度大,还是学习React难度大?答案显而易见。

难道上了一个框架写法统一了之后我们不需要学小程序了?可能性不大。即便是移动端这个相对稳定的平台也尚且不能做到,根据我一些移动开发同事的反馈,React Native确实能完成许多的业务场景,但有不少问题你还是需要通过编写的Object-C或者Java代码才能够解决(抱歉,我们公司还没有上Swift以及Kotlin)。

这似乎得替移动开发群体喊冤了,以前做移动开发懂Object-C或者Java即可,然后便是深入相关领域,学习调优,工资还蛮高,工作也好找。如今所谓的统一写法的“最佳实践”流行之后,除了懂这些之外还得另外学JavaScript,React Native,以及一堆的预编译工具。工资水平却似乎却不如从前了,工作还不好找。但本质上要解决的问题似乎跟以前没什么差别,这想想不也挺折腾的吗?

2. 真的解决了问题?

我们都知道一个叫做80/20的定律

80%的事情其实花费了你20%的时间,另外20%的事情将会花费你80%的时间。

请允许我将这个理论用在小程序上,我个人比较幸运,没什么机会开发小程序,以至于我可以用旁观者的身份来观察身边同事的工作。从他们的开发经历来看,开发一个微信小程序,只要是客户还算理智,正常的业务逻辑其实并不会耗费掉多少时间。小程序的价值不就是简单轻量吗?

然而小程序有个问题就是平台不够稳定,更新频繁。这个过程可能会修复掉一些Bug,但也可能会引入一些新的Bug。往往一个业务不怎么复杂的小程序为了“掩盖”这些问题所花的时间都要赶上业务开发的时间了。试问上一个封装程度更高的框架就能够“修复”这种问题吗?我感觉这像是沙堆上建房子。另外,大家遇到的业务场景不一样,你遇到的问题他不一定会遇到,因此我不相信一个基于不稳定平台的抽象能够自动处理该平台本身的问题。

这让我想起美剧《硅谷》里面盖文.贝尔森的对白

请大家想想有这么一个革命性的功能,一旦整合进“纽核力”平台,可以修复平台发布过程中出现的任何问题。

GB

他真不愧是21世纪最不切实际,最会忽悠并压榨员工的科技公司的管理者,而且这种类型的管理者似乎也不在少数。可悲的是,这也是很多人上一个框架的初衷,觉得框架会帮我们修复一些我们自己不愿意修复的问题,别做梦了,世界还是很残酷的。另一方面,使用一个基于不稳定的平台开发出来的框架,出bug的几率还是比较大的,当bug出现的时候,你可能还要花时间去定位是微信自身的bug还是开发框架所带来的bug,这都是比较耗时的工作。而这种时候,到底框架帮你解决了什么问题呢?

关于写法统一的问题,在2016年的RubyConf China里面一个叫Terry的演讲者(他现在是Nervos Network的CEO)在会上讲过一句话对我影响很大,大意如下

我发现今天的Web开发跟十年前相比并没有什么不同,既然十年前我们就用Ruby来写后端,用JavaScript来写前端交互,为何十年后的今天我们一定要统一写法呢?

回过头来看,这些业界所强加给你的最佳实践可能并没有你想象的那么的“最佳”。作为程序员我们是被雇佣来解决问题的,请尽量别让自己把问题复杂化。

前后端分离是最佳实践?

前后端分离到底是不是最佳实践?不同人会有不同的看法。在我看来解决问题才是目的,分不分离都只是手段罢了。 随着React,Vue这些框架的盛行,不分离者成了众矢之的,因为业界都觉得分离才是“最佳实践”,确实前后端分离可以让前端专注于自己的开发流程,但有的时候前后端一旦分离,挣脱了后端约束的前端便犹如脱缰的野马,一小心就成了Rei所说的前后端分裂了。

在充分利用Webpack大杀器之后,我们甚至可以用自己喜欢的任何语法来写前端程序,渐渐地可能会发展成一种只有自己才能够看懂的DSL,熟悉的人自然得心应手然而其他工程师要学习,理解,并且提出质疑都会花费彼此不少的时间,这都是成本。我始终觉得如果一个前端工程师写的代码后端需要花费很大的力气才能够读懂的话,那或许应该稍微反省一下了,是不是某些地方过度工程了?

前后端分离是把双刃剑,需要前后端人员相互协调项目才不至于失控。需要考虑分离带来的好处是什么,是为了表单提交更方便?还是为了页面交互更加流畅?并不是说Facebook出了一个React,而它用这个框架重写了Facebook还有instagram这些网站我们就一定要跟从。有时候还得考虑Facebook这些公司什么量级自己什么量级。如果只是需要提升部分页面的交互效果,或许Gitlab这种只把关键部分的资源进行分离的做法会更适合我们。不考虑实际情况,只是为了脱离后端把控而实行的分离在我看来都是搞事情。

最佳实践有时候会让你远离问题的根源

这是最近公司进行容器方面尝试时遇到的问题。最近升级官网服务,想要基于这个项目做一些容器化的探索。初步的预想就是脱离原始的capistrano部署方案(这不是一个好主意)然后

  • 对官网项目容器化。
  • 基于容器实现自动化部署。

OK,理论上我只需要学习如何用Docker相关的技术来容器化整个项目,然后再使用辅助工具来实现自动化部署即可。而这个时候运维小伙伴为我引进了Kubernetes(K8S),这个业界容器化的“最佳实践”。这是个好东西,但同时也给我带来了其他的问题

  • 根据K8S提供的最佳实践,我们需要把配置文件存在Etcd(一个配置管理服务)里面。
  • SSL证书要如何管理,是否应该采用更流行的Caddy服务?
  • 服务多了要怎么做反向代理?K8S有现成的东西可以用,以后做扩容也方便。
  • 有那些服务需要挂载数据卷?

好吧,在对K8S没有什么了解,并且没什么运维经验的人来说要消化这些问题难免需要点时间,我就花了一两周的空闲时间去看K8S的文档,其实要熟悉K8S的命令不是很困难的事情,但是要理清不同服务之间的关系,并实现对应的“最佳实践”却是比较头疼且耗时的工作。这期间还有一些其他项目的干扰,导致了新版官网迟迟没有得到部署,因为精力都花在别处了。

后来才醒悟过来,好像我们都沉浸于业界的最佳实践当中,被一堆所谓的最佳实践的概念所淹没,而忘记了一开始我们需要做的事情以及要解决的问题。其实我们想要做的本质工作只是把项目部署出去,最好是能够自动化。K8S以及相关的最佳实践只是可选项,我们沉浸于最佳实践当中,却没能尝到它带来的甜头,离问题的根源越来越远。

大家都倾向于实现一个100分的解决方案,却没有考虑到要做到100分所要付出的时间还有精力,或许很多时候一个60分的不甚完美的解决方案更适合自己。因此最终我们还是决定只完成容器最基础的部分,然后尽快把项目部署出去。K8S的事情延后,在以后的日子里再慢慢去优化这个只有60分的解决方案。

最佳实践让你束手束脚

这是一个“先有鸡,还是先有蛋”的问题。以前的人做开发普遍都是撸起袖子就干,等到经验有所积累之后慢慢重构已有的东西就得到了我们手上的框架。也就是说前人是先解决问题,然后把通用的解决方案抽象成框架,现在的人似乎不太一样。而如今许多开发者是遇到问题,先找最佳实践,如果没有最佳实践甚至不敢着手去解决问题。或许这也是Linux内核的开发者林纳斯曾经怒斥最佳实践的原因吧。他说

最佳实践很多时候就是狗屎。

当“最佳实践”成了一种思维的束缚,成为解决问题的巨大门槛的时候,它还算是最佳实践吗?当一个开发者被一个框架的思想所束缚,离开了指定的框架就无法完成任何工作的时候,那这个框架存在的意义又何在呢?还记得《倚天屠龙记》里面张三丰教张无忌太极拳还有太极剑的时候让他干嘛了吗?忘掉所有招式。如果这些所谓的招式对一个人来说只是束缚,那么还要它何用?

实际上很多时候你能够想出的解决方案已经足够好了。不可能有人一开始就能够把事情做得完美,Ruby On Rails经过了十几年的洗礼,至今还有许多可以优化的空间,市面上那些琳琅满目的框架有几个经历过这种时间的沉淀?

Erlang语言的创始人Joe老爷子曾针对一门语言不够快而发表过这样的言论

先把程序写正确,然后慢慢优化,许多年后它就会变快了。

比起一开始就追求高性能,最佳实践,或许有些时候我们可以先考虑如何把“程序写对”,哪怕这个解决方案不是最佳,起码你为这个问题思考过,而不是想着拿来就用。如果以后遇到更好的解决方案,我相信到时候再优化也为时不晚。

总结

以上是我对软件开发过程中“最佳实践”这个观念的一些碎碎念,我个人并不是完全排斥最佳实践,但是我认为所谓的最佳实践是有场景限制的,考虑到时间成本,实现难度,人员调配等各方面因素,在某些场景下的“最佳实践”在另一些场景下或许会成为“最糟实践”。什么都不想就随大流,强上“最佳实践”的做法无论对自己还是对团队都是极度不负责任的。

共收到 31 条回复

观点中肯,适合的才是最好的。。。

写的很好, 优雅和实用达到平衡才是最佳实践

统一写法的好处主要是降低技术成本吧。如果项目组已经有一套成型的技术选型,那么用 Taro 这类跨平台的框架开发小程序可以让开发人员的经验得到最大的复用。除非项目组人员流动很大,新老交替频繁,才需要思考 “学习小程序难度大,还是学习React难度大” 。从 react-native 和 flutter 来看,跨平台还是主流倾向。

至于前后端分离,对于 “前端工程师写的代码后端需要花费很大的力气才能够读懂的话” 这种情况,作为前端工程师我是能接受的。分离出前端和后端这两种岗位目的就是为了各司其职。再说现在小程序出来后,不说 react 这类技术栈,至少跟以往 jquery 加 html 的方式也不一样,难道开发小程序也得前后端一起学吗?在开发 app 的时候也不会要求后端去看 app 的代码吧。

个人觉得,前后端分离的方向,跟小程序、app 开发是类似的,后端去限制前端的技术栈是不可取的。 而且代码需要前后端都能看懂的想法,会不会跟 “统一写法重要吗” 这种观点相违背呢?

jamieYou 回复

首先感谢你的长篇回复,至于统一写法是降低了技术成本还是提高了技术成本并不能单靠是否只需要学习一门语言来衡量。这个一个人说了不算,需要考虑到团队的情况,以及会带来的问题。

至于后端会不会去看我的代码这个我没办法控制,我说的 “前端工程师写的代码后端需要花费很大的力气才能够读懂的话” 其实只是一种不太严谨的约束,其目的是为了不让项目脱离掌控,我的意思是就算前后端分离了,也应该从项目角度来全局考虑一个方案是否合适。我不会要求后端去看我的前端代码,但是我觉得让代码通熟易懂是很重要的,在某种程度可以尽量降低后端(可能前端也是)审阅代码的成本,因为这对我而言才是真正地降低了技术的成本。

后端去限制前端的技术栈 请不要曲解我的意思,如果你认为让代码尽可能通熟易懂是一种对前端技术的限制那我也不好说什么了。

sharpx 回复

谢谢,但是有时候这种平衡也不好把控,特别是在这个选择太多的时代,我们都倾向于把最新最酷的东西加进去。但是很多时候在后面才发现有些东西其实有点“鸡肋”了。个人能力有限很难把握好这种平衡,有时候太保守了也可能后面会觉得保守过头了,只能在项目演化的过程中不断调整脚步,并总结经验了。

xifengzhu 回复

就你最能捧场,谢谢。😀

7楼 已删除
jamieYou 回复

虽然我们观点不合,但是也感谢你特地跑来捧场。😈 😈

lanzhiheng 回复

"代码通熟易懂" 这块太主观了。 我觉得你说的问题主要在于没有一个大佬去管理技术栈,去定义好开发规范,才会导致这些问题。

曾花了整整一周去折腾如何在混合云上搭一个人 K8S 集群,最后还是放弃了,swarm 真香

IChou 回复

曾经操作过这两个东西,用起来感觉很像 👀 。不过之前听一些朋友说swarm很多坑,具体没去考究,不知道是不是真的。

lanzhiheng 回复

一般说“很多坑”估计是缺了几个小功能,追问一下就知道了,如果真有坑的话,他会用“特别坑”来提醒你 😄😄 我这边用着很好,配合 portainer 爽歪歪,关键是不折腾啊

jasl 将本帖设为了精华贴 01月28日 14:29
IChou 回复

哈哈,其实我也就用Digital Ocean的api来创了两个实例操作了一下而已,其实没遇到什么大坑,因为不够深入。

其实小程序不想用官方的就一个原因,太麻烦啰嗦,倒不是为了统一什么写法,小程序官方用的类vue写法,却一个页面四个文件,而且很多js的语法特性不支持,用mpvue或者taro是可以节省不少事,当然了,也有不少坑,这个要看怎么取舍了。

先把程序写正确,然后慢慢优化,许多年后它就会变快了。

最佳实践是有上下文的,有些人出于推广自己的目的,隐藏了上下文;有些人长时间处于某个上下文,说的时候反而忽略了上下文;有些人明确指出了上下文,但是刚不住,一帮只会看一半的二逼呀

zouyu 回复

我也觉得是有上下文的,最佳实践是基于你的团队、你的项目、你们所用的技术所产生的。不能直接套别人的吧,不然很容易变成卖家秀/买家秀,明明别人穿着很好看,到自己身上怎么那么别扭呢?因为身材气质不一样呀!

这本身就是一个开放话题,觉得没有好与坏之分。团队适合什么的技术栈主要从人员素质,开发成本,产品规划考虑。对当前有利,又适应未来产品发展的就是好技术栈,也就是白猫黑猫理论吧。

我认为解决问题的方法就是寻找最佳实践. 最佳实践能够避免后来者重蹈覆辙. 但是最佳实践只是一个名词而已.如何找到最佳实践,每个人都有自己的一套方法论. 比如我的

  1. 官方推荐 (最高优先级)
  2. 主厨精选 (次优先级, 这里的主厨通常是一些大企业的解决方案, 如Google/facebook/国内的阿里等等)
  3. 尊重多数人的选择, 实际上官方在做选择时应该也会尊重多数人的做法
  4. 简洁之道,当时间较为紧迫,没有办法寻找最佳实践时,我会凭借自己的经验来解决(自己的经验与习惯往往是不可靠的,其可能就是年轻时拍拍脑袋产生的,然后一直沿用至今,自以为非常优秀). 但是我用自己的方式来解决问题时,简洁之道占据了最高优先级

上面也算是是google问题时的参考顺序哈哈

@lanzhiheng 前后端分离挺好用的啊,后端只需要写好逻辑就好了,很focus,很符合经济学原理 里头的分工理论,即甲乙产出A,B产品,即使甲A,B产出效率都比乙高,分工也效率更好, 让甲专心做A,已专心做B,出来的效率也比甲乙都混合做A,B高(经济学原理第一章)。目前实践下来挺方便的, 除了后期调试bug要复现他们所说的bug的时候不太方便以外,其他都还好。至于之前有个人说什么 前端莫名奇妙做缓存导致改api变动出问题,那是前端程序员的问题吧,依赖一个不存在的约定。

另外,部署为什么要用Etcd,我们用apollo.另外docker部署确实快,现在一个改动push下去, 都是几s就好,最近几次都是7-8s, 比cap,mina什么的快多了。得益于docker的layer机制。

其次,你们运维就简单的搭了k8s么,其他都不管的么。那这怎么实践最佳实践啊。我们运维 负责把环境全部搭好,我们只需要把builder好的docker image给他就行了,做CI/CD。

所以,没有做最佳实践,估计还是做最佳实践的各个组件,或者一部分组件(指人)没有做好吧。 那我这边再好的插头,没有插座也没用啊。国外那帮推最佳实践的,总体的实力都比较强啊。 就像之前的敏捷,传着传着就变形了。很难做到copy不走样。

对了,那个apollo的搭建,也有运维人员的帮忙。

如果所谓的「最佳实践」大幅增加了工作量,那就得认真考虑。另,我觉得一部分人喜欢用 JavaScript 来「统治世界」纯属一种奇怪的执念…对一个熟练的前端来说,学会用 Sinatra 这样的框架来 Mock 一些 API 还能学不会不成?

femto 回复

意见很中肯,其实我个人是不反对前后端分离的,好像许多读者都误解我的意思。我其实反对的只是两点 1. 不考虑实际情况盲目分离。 2. 不考虑上手成本和代码可读性而不断堆积最新语法(当然似乎每个人都觉得只有自己的代码才是可读的,这就没办法了)。 在有些场景我们其实也不得不分离吧,比如一个重交互的应用如果用jQuery去写是很闹腾的事情,这种时候我会考虑分离的。只不过如果是个人选择的话我会选择Webpacker这个Gem,毕竟我觉得并不是所有场景都需要把整个站点去分离。

内容不错,但的确是标题党了,k8s和容器化的最佳实践搭不上边,跟着实际情况去选择最佳实践,不是按着最佳实践来压你的实际情况,这实际情况不仅包含场景需求,也包括团队能力,长期运营需求,等等,这个所谓的受害者不是最佳实践伤害的,是自己选型犯错而已,而且,这犯错其实也是一个宝贵的经验,看怎么去看待问题了

我看到是 很多时候是你自己不会玩,然后就说“最佳实践” 是个坑。

最佳实践对于不需要了解细节的东西来说,是最好的。。。

所以人类才建造不了 巴比伦塔 啊

维基有这么一个介绍

A best practice is a method or technique that has been generally accepted as superior to any alternatives because it produces results that are superior to those achieved by other means or because it has become a standard way of doing things, e.g., a standard way of complying with legal or ethical requirements.

还是看你怎么理解最佳实践吧 你的团队有你团队的最佳实践。业界有业界的最佳实践。 比如你说的装饰器,并不在规范里。

xiaohesong 回复

我相当同意。所谓最佳实践应该是基于前人方法以及技术的较为通用解决方案的总结。通俗来讲应该是“道” 层面上的东,不过现在很多地方都演化成“术”层面上的东西了。每个人的开发方式可能还有习惯都不太一样,把“术”都定死了难免让人觉得无所适从(当然团队协商结果就另当别论)。

只能说有事会是吧

最佳实践的本意应该是为了提高可读性(包括给别人看), 方便维护, 不过有些情况是有些程序员连最佳实践都不了解就按照自己方式写, 还有些用其他语言(语法差别较大)的最佳实践去写代码..., 导致团队后期维护代码非常麻烦😳

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册