我眼中软件工程人员该有的常识

# 背景

说起工程人员/团队应该具备的“常识”,真正促使我认真思考这个问题,还是因为知乎的一篇贴跟没有常识的人聊天是一种怎样的体验?,里面笑料百出,各种由于“常识”不足导致的尴尬癌真真是忍俊不禁。但笑过之后我发现,所谓的“没常识”,可能由多种原因导致,这点在知乎里多位答主都提到过:

  1. 信息不对等 - 大家所处环境不同,对“常识”这样一个相对概念本身囊括的内容就有不同定义
  2. 道德水准低下 - 虽常被归类为“没常识”,但通过仔细甄别是可以分辨出来的
  3. 逻辑混乱 - 可见于24种常见的逻辑错误 – 作者:谢至理

抛开第二种暂且不论,就1、3而言,在我们软件工程中,这些原因是否可能导致沟通成本提高、工作效率变低呢?下面结合我自己的痛苦经历来谈谈“常识”的故事!如果我下面所述你早已烂熟于胸、甚至还有补充,恭喜你,你为自己所在团队增添了一抹幸运!如果你对里面的部分内容还不清楚,或许那正是你需要的。

# 操作系统是不同的

Windows 与 OSX

sense

大家可以看得到,左边是osxfinder,右边是windowsexplorer,无论从UI设计还是功能设置,他们都有很大的不同,譬如:同样是小叉叉,但在两个操作系统上功能是有差异的。

IOS 与 Android

sense

如图,同样是facebook的应用,左边是IOS版;右边是Android

有个人喜好没有问题,但如果生硬的将之带入工作中,并固执的忽略操作系统间的差异就会影响到工作质量。

我曾不止一次看到有测试人员为osx应用提了bug - “[OSX]点击关闭按钮应用没有完全退出”;

又有人为windows应用提bug - "[windows]ctrl + q快捷键不起作用"。

但是大哥,真心的,如果你实在懒得不想去了解两个系统到底有哪些不同,也最好静下心来听别人说说,至少你得承认操作系统是不同的。

这个问题上,我认为,作为一个软件工程人员,首先应该理智的承认——操作系统是不同的

# Web不只是前端的事儿

# 跨域问题

近年来由各大巨头公司猛推的前后端分离炒得火热,不过我发现实际操作中一些团队都受困于对跨域问题的理解。举例:由于前后端团队对跨域问题的理解程度不同,甚至有时候是都不了解,导致当错误发生时,前端找后端要求支持cors,后端反问“那是什么东西,你都说不清,我不能帮你”。搞得最后连postputdelete等方法都要上jsonp,试图绕过跨域问题,可jsonp毕竟是有局限的,这里我们不过多深入,各位可以参考构建public APIs与CORS

# restful

之前合作过一位后端“大神”,他说自己的API设计扩展性超强,是真正健壮的restful接口。于是我请他讲解,其口若悬河道,我的接口直接把前端和数据库打通,你们直接传数据库字段和对应值,我一一帮你录入数据库。当我问及,那会不会被人利用黑我们数据库,导致大量废数据产生,“大神”鄙夷的看我一眼说,你自己都说是废数据了,业务不通,是不会显示在用户界面里的,怕什么!可我想说的是“大神”啊,坏人可以分分钟干爆你的数据库,这么“透传”真的是扩展性好么?

还有一事,对于一个数组字段,没有值的时候到底是返回null还是[]又成了一个问题,一位友人和我强调他们后端就是要返回null,理由是"java语言设计了null,那么返回null就是最好的选择"。于是我又默默的去一边呵呵了。

我们并非要求每个人都对restful的各种约定、要求倒背如流,但网上关于restful接口设计的经典案例、最佳实践,一搜一大把,而且内容都不多,既然都说自己在用restful了,那么看看别人的最佳实践,不过分啊!

# URL

url

一个URL到底由哪些部分组成,各部分的学名又是什么,我猜你可能已经发现周围有人不知道了。我曾见过两个在讨论subdomain问题的人,然而1个多小时过去了,也没什么结果,吵得不可开交。后来我让他们画下自己说的到底是URL的哪个部分,结果发现二人说的所谓subdomain根本不是同一个东西。

既然大家都在互联网圈子混,能够准确指出URL各部分都叫什么名字,专业且沟通成本低,不过分啊!

# 渲染?

经常看到有朋友问及类似:“AngularJS里有模板,我们公司用Node做服务端也有模板引擎ejs,二者能否混用,如何混用?”,其实这种问题多见于初入门者,没搞清楚的“前端渲染”和“后端渲染”有什么区别,而且基本可以断定对一个URL从敲在浏览器地址栏起,到页面最终显示出来,都经历了哪些过程?所以你可能需要知道当你输入一个网址的时候,实际会发生什么?。然后还需要搞明白“后端渲染”到底是什么,最后再回想你关于"混用"的问题。

# 复用

“复用”这个词我们天天见,就像“大宝”一样(年龄暴露),但复用都有哪些层次,这个问题就有点意思了,我想了想,大概可能有以下几种吧:

  • 拷贝、粘贴 - 这应该是最常见,也是最简单粗暴,容易理解的那种了。你写好,我来拷贝、粘贴到我的项目里,复用达成!
  • 运行时复用 - 以前网站开发中常见的模式,一个css文件,所有的页面样式都在里面;一个js文件,所有页面的业务也都在里面。好处是你真的不用关心谁配谁,反正一共就俩文件,坏处也显而易见,当你要优化网站时,可能想要需加载、可能想剔除不必要的代码、也可能只是想按业务拆分代码,立马让你抓瞎。
  • 开发时复用 - 在browserify, webpack, rollup之类打包工具的诞生以后,前端圈子也越来越注重这个层次的复用。各种资源都可被定义成“模块”,在开发过程中按需引入,rollup甚至还具备了tree-shaking这类神一样的优化能力,使其更显逼格。

至于你在项目中需要采取哪种复用,这就看你自己对复用的认识和项目本身的需求了,但无论如何,复用真的分不同层次,这点作为软件工程人员你是需要知道的,而且在团队沟通中,最好统一大家的认识,以免驴唇不对马嘴

# 自我驱动

“学而不思则罔,思而不学则殆” - 孔子在2000多年前就讲了学习和思考的关系,我们活在当下,又怎么能超脱!?

我们常常在工作中遇到这样那样的问题,有时候人们是这样回答的:“我们的业务非常特别,对于这个功能,无法支持”。首先我相信世界上有些功能的确做不到,但这种话听多了就会奇怪,你的业务真的就那么“特殊”么?或者说,你遇到的技术问题,就那么“唯一”,网上一点痕迹都找不到?

其实我想说的是:

sense

但为什么你就是找不到问题的答案呢?总结了一下我多年的工作经历,我发现以下几点是造成“无解”假象的主要原因:

  1. 第一名就是不会善用搜索引擎,尤其不会善用google。还记得多年前曾带过一个实习生,他说没办法在servlet里获取请求的query参数,我大惊并质疑其答案的正确性,他说反正在google没找到结果,随后即猜测应该是必须引入框架,仅凭servlet应该是无法拿到参数的。对话进行到这里我基本断定是他的搜索姿势不对了,因为就问题而言真的没有那么special。当让他展示搜索过程时,他在搜索栏写到"i have an issue about retrieving url parameters, which is balabalabala"。也许你可能会笑,但这是我们工作生活中经常遇到的可爱的人,或许他们真的以为网络的另一头有一个大神正戴着耳机,眉头紧锁的盯着屏幕回答来自世界各地的问题呢(尽管他自己也是个工程师,但仍然会迷信的认为后面有什么不为人知的大招儿)。在使用搜索引擎时,准确的分解、抽象问题,并且使用友好的分词组合是非常重要的手段,也是在人人平等的搜索引擎里,你如何脱引而出的根基
  2. 坐井观天一定稳坐第二把交椅,不少朋友对于新知识是深恶痛绝的,他们善于利用已知的(仅有的)知识来解释自己未知的领域,譬如常见的观点有:管他什么声明式还是命令式,我都不关心。我就是要写$(...).show()/hide(),多直观的代码啊!你去搞什么AngularReactvue,弄些什么数据驱动,都是吃饱了撑的。这些框架最后不也都乖乖的做DOM处理?与其等框架处理,我自己写不好么;管他什么模块不模块,我一股脑的写完脚本,最后concat -> minify一下,不也是一个文件么,乱七八糟的又是commonjs、又是ES6,还有什么AMD,看的头都大。======有自信是好事,但在不了解背景原因的情况下,生硬的拒绝并不是高明的表现,或许数据驱动不适合你,但你确定已经掌握数据驱动要解决的问题了么?或许模块化不适合你,但你又搞明白了ES6是怎么解决循环依赖的问题?AMD最早是为什么被提出的?

说实话,没有谁是与生俱来的the one,我们大多数时候遇到的业务模型,也没那么举世无双,不耻下问、兼听则明,只有不断的鼓励自己多学、多看、多听,多想才有机会跻身前列,或者说,起码可以做个对得起自己职业的人。

# 忙碌 !== 高效

下面绝对是张大家相识已久的图,我就不多说了

sense

有位朋友是这么评价图里推方轮子的人的,“你永远没法叫醒一个装睡的人”。

对于尸位素餐者,想必也不会来看我这篇东西,也就不用给出什么提高的建议了,因为他们“不关心”

但对于团队管理者,以及团队其它成员,你们要注意的是,团队现在的状况,到底是高效率的忙碌,还是使劲推着方轮子在赶路

# 责任边界

sense

有朋友可能会对该图产生疑惑,其实这里我想说的,软件工程团队讲求合作,合作首先要求每个人把分内之事做好!

我们常在工程师论坛看到人们抱怨PM的不专业和拍脑袋,总需要开发擦屁股、背黑锅。但话说回来,这个事情真的没有改进空间,没有避免的可能么?

我们先假设工程师说的都是对的,问题就是出在PM身上,那作为一个团队,除了抱怨,你就没有责任帮助他提高么?你可能说PM的专业技能包含好多,我不会怎么帮?但沟通技巧、注意事项总是可以帮的吧?有人又说,PM趾高气扬,即便我想和他说说沟通的注意事项,他也未必听我的。接下来我想说的就是针对这类牛逼的合作选手的腹黑手段(当然也会迫使对方自我提升)

我经历过一个团队,每次要从PM、设计师那里拿到需求和设计,但是由于PM和设计师的不专业,他们提供的需求里往往仅包含正确逻辑,譬如:一个登录页面,只告诉你用户名、密码都输入正确时的应对场景;但没有说,用户名没输入怎么办,输入错误怎么办?密码没输入怎么办,输入错误怎么办?用户名、密码的格式要求是怎样的?这些交互上的其它问题他们都不管了。于是我们的开发就和爱心妈妈一样,自己把可能遇到的问题,以及UI该是怎么样的,全部都开发一遍,然后demo给PM/设计师,让他们挑选一款,其余的再删掉!我去,这是多大的开发资源消耗啊!团队给我的答复就是,他们不懂,没办法,只能我们做了给他们挑。于是开发进度被拖慢,谁之过?PM说了,开发团队不给力,做的太慢!开发质量不够高,常常一堆冗余代码删也删不干净,因为不知道之前哪个设计待选稿里加的,删除时忘了,谁之过?PM说了,开发团队不给力,多版本处理不当。设计、交互不够好,谁之过?设计师说了,开发团队不给力,做东西东拼西凑还总是错。

我去,这让我想起了东郭先生和狼的故事,我们辛辛苦苦帮你PM、设计师做你们该做的事,完事还被反咬一口!但仔细想想,问题的原因不是他们坏,而是开发团队模糊了团队协作时每个人的责任边界,我们当然需要亲密无间,但这不表示个体之间责任可以混乱。能者多劳固然牛逼,但任何角色都应该按质量完成自己分内的工作,这里开发团队只要咬死需求缺东西、设计不完善,迫使责任人修正就好了,而不是一味的帮他人善后。

# 自动化测试

说起自动化测试,常常有人会站出来反驳道,反正做不到100%的覆盖率,而且花费时间甚多,何必浪费时间写各种测试用例。这是一个重大误解,自动化测试及其意义我们可以看到以下几点:

  • 更省钱 - 对于稳定的功能(常见于回归测试),可以做到一次编写,多次运行
  • 更快速 - 对于相同的测试内容,自动测试显然要比手工测试快
  • 更可靠 - 对于相同的测试内容,自动测试的结果显然也比手工测试更可信(人是有可能犯错的,譬如:分神了)
  • 更低风险 - 对于项目转手的情况,如果有自动化测试,更利于再维护
  • 更强大 - 自动化测试可以模拟1w甚至100w人同时访问的并发状况,手工测试则仍然需要借助工具,否则无法完成

# markdown

markdown作为一种轻量级的“标记”语言,越来越受欢迎,无论是Githubstackoverflow还是segmentfault,都支持markdown编写、提问、回答。

不要被“语言”两个字所吓到,其实markdown超级简单,容易掌握,而且话说回来,不会写markdown,你就连在stackoverflowsegmentfault上提问都做不到格式整齐,还指望别人根据你混乱的描述回答你?别闹了好么,大家都挺忙的!

# 没有银弹

无论你遇到了什么问题,需要引入额外的技术手段,或者流程来解决,都一定要先了解即将引入的技术、流程的背景,工作原理,然后正确、准确的使用,否则事倍功半。

我见过不少人/团队,听说AngularJS好,都没仔细看明白人家到底解决了什么问题,就直接一股脑引入到自己项目里,胡乱使用,在controller里操作DOM,在service里也要操作DOM,出现问题后反而到处抱怨说Angular就是狗屎,我们用了半天,什么问题没解决,反而出了一堆错

也见过有团队听说scrum有助于提高团队工作效率,就引入了,甚至都没有做系统的scrum培训。结果导致连最基本的形式流程都做的缺斤短两,更别提深层次的理论结合实践再创新了。结果就是场面一片忙乱,但效率却丝毫没有提高。于是又到处批评,scrum就是一帮闲着没事的人搞出来的蛋疼产物,除了耍人,没有卵用。

这种思维方式就是《建党伟业》里辜鸿铭说的:“孔子教人之方法,如数学家之加减乘除,两千年前是三三得九,今日仍是,不会三三得八。自家学艺不精将题目算错,却怪发明之人,毫无道理”。

# 开发和测试的关系

当你认为开发和测试是敌对关系时,你就进入误区了。开发、测试不必你死我活,也不必互相仇视,大家是在一个团队,为同一个产品贡献力量,正确认识团队,正确认识合作,才能使我们走的更远

# 结束语

关于软件工程团队里的“常识”,我相信仍有好多内容需要普及,所谓普及,并不是要求诸位关于上述的每一项都成为专家,而是时刻怀有敬畏之心、进取之心、钻研之心。坦白讲我不是什么高手,但我热爱我的工作,我希望把它做好,也鼓励入行者都热爱程序员这份职业,以上篇章或有疏漏、错误,欢迎指正!