今天,在知乎看到一个问题,“4个月写了4万行iOS代码,算多还是少呢?”,这是一个没办法回答的问题。我一直用代码行数衡量我自己的项目,但是在我对一个人不了解的时候,他的代码行数多少对我毫无意义。这是一个相对指标,自己衡量自己很好,衡量别人是完全不充分的。
这是我的详细解释:
如果你不是进行非常特殊的项目,或者说你技术非常牛的话,我会认为这可能说明你的代码质量太差。Objective-C是一种非常高级的语言,Cocoa是一个非常完善的框架,用这两者写代码,代码应该很简洁。
我们在做的一个项目,是非常复杂的交互排版系统,支持各种文字绕排效果、视频、Keynote、各种交互,等等等等,代码行数也才2万行。当然这需要了解你的具体情况才能准确评估你的代码是好是坏。如果你在做一个很复杂的项目,比如说,做App的话,各种不同的窗口很多,加入你有1000个不同的窗口,那么代码多点也可以理解。再或者你实现了某种复杂的通讯协议,代码多点也正常。
代码不是一个完美的评估项目的标准。以前有一个故事是说,项目经理用代码行数来衡量工作量。结果程序员就开始增加代码里面的空行,本来函数结果会有一个空行,现在放两个。再后来,有个程序员写了一个编译脚本,每次编译前在代码后面就自动加一个空行,这样有时候就算什么正事儿都不做,光是编译几次,自己的日工作量就可以达标。这些都还是简单的,真的要糊弄人的话,让代码变长的方法很多,比如,可以把一个资源文件,比如图片,转换成一个常量数组,那代码尺寸膨胀的可以想多快就有多快。
但是更多的时候,代码的无序膨胀就是代码编写习惯不好,也没有经过专业的训练。很多年前,我在某公司咨询的时候,见过这样的PHP代码。一个页面几千行,没有任何函数关系,一以贯之。我当时就跟客户的程序员询问他的写代码习惯,他就说按照逻辑一句一句写,遇到类似的逻辑就复制粘贴,这样代码当然就越来越多。我就问他有没有觉得这样写代码很累,他说一点都不累。然后我问他,当代码出了问题,改起来容易么。他就快哭了。然后,我就教他怎么,去把重复的代码凝结成函数,抽取结构和参数,提高复用级别。
这部分听起来很简单,但是实际上,这是一个极端的例子而已,大多数从业者可能知道怎么构成函数,但是在代码里面,仍旧是复用级别太低。也许你是用面向对象的方法去编程,但是基本的逻辑是一样的。
那就是重复的代码,一定要被合并成函数,或者是类的方法。这样首先是节约代码,但是更重要是,结构开始展现,从彻底的面条代码变成有条理,有结构的代码。人的认知能力是有限的,记忆能力是有限的,屏幕尺寸也是有限的。当你把几百行面条代码变成,几个函数以后,首先,你用来理解代码的单元变化了,从大逻辑上,你可以把每个函数当作黑盒子,总体结构就变成,调用几个函数了。然后当发现系统有问题,且你怀疑出在某个函数内的时候,你可以只分析这个函数的输入输出,就可以定位问题是否是在这个函数内。确定后,你修改和去理解的难度也大大降低。
以前有一个原则,叫做重复两次的代码块,必须函数化。一个函数尽量在几十行内。不见得非要100%的严格执行,但是建议认真体会,时刻反思。
写代码的过程应该是,先写厚,然后再写薄。写一段时间就反思一下,实现的结构是否合理,是不是太过冗余。当你的代码总是能保持一定的结构和复用程度以后,代码行数就会是项目规模的良好评估参数了。多一行,就说明逻辑确实复杂了一层。如果形成这样的习惯以后,随着代码量的增长,你的功力自然会加深。
其实写程序,就是一连串逻辑,你可以抽象他们,也可以具象他们,在看全局的时候抽象,可以帮你思考问题,看清big picture,可以理清头绪。当做具体实现的时候,你可以回到具体的细节上,但是,有了全局的抽象结构,你可以只关心一个局部的细节。
刚才我和我们公司主程在商量新产品的开发步骤,我跟他回忆我们之前开发这个2万多行交互排版系统。我说,如果我们一开始,一个模块一个模块的从头做起,一步一步做精,那么也许我们做几年才能做完。但是实际上我们是先把每个模块都定义好,实现了一个空架子,然后一点一点完善。这样有几个好处,第一,这东西是可以持续集成,边开发可以边测试整体效果,可以不段的改进,不需要瞎子摸象。然而,我们实际上,从始至终可以掌握进度,可以看清轻重缓急。这样,这个项目才可为,否则就完全不可控。
当你能顺畅的切换你的抽象层次,你其实就明白了什么是架构。
其实我最大的问题是,你们自己写了多少代码是怎么算出来的?即便某工具可以看到某项目代码总行数,但是你怎么知道自己写了多少,别人写了多少?加逻辑,加业务这部分怎么算的,就没有在原有逻辑上动过?可能独立开发者好算点,但团队开发基本就不知道自己写了多少吧。比如我就有时候很快写出很多,有时候想很久写出一点点,从来不知道自己写了多少行,也不知道重构让代码减少是否算新写的行数,更不知道写了多少行代表什么,见到能清楚知道自己写了多少行代码的非独立开发者总觉得很神奇。
转回我在知乎的回答:
4个月4万行,假设你6x12工作,每小时138行+提交。
从码字员角度,看,真少。
但根据我10年来当工程师的经验(我自认是3流程序员,不过还好我的所有leader都觉得我还过得去),每小时100+代码提交(假设这都是业相关代码,而且是你手写的)是非常厉害的。
因为在实际工作中,你面临着业务需求的变更与明晰、技术方案的研发与明晰,算法的理解和实现,折腾开发环境、处理异常事物、高频调整重构代码、必要文档的编写,与团队的沟通,诸此种种,全是时间大块的占用。
从工程师角度看,真多。
兄弟,你很棒。
当然,无论是管理者还是程序员自己,企图用代码行数来做kpi,都是愚蠢的选择。你的一行代码能产生多少价值才是关键。
代码应该是越短越好。有时候就是改一下解决问题思路,代码也可少n行。n 可以很大。 你是喜欢写个fibonacci 随手洋洋洒洒几千字的程序员,还是喜欢惜字如金但是解决(避免)很多问题的程序员呢?
如果单纯用代码行数来评估程序员的工作成绩,肯定会不公啊。
假如某个非常复杂的业务逻辑,技术含量非常高,但是可能编写的代码行数较少。
再假如某个较为简单的业务逻辑,技术含量一般,但是因为操作频繁所有代码量较多。
这样的情况这下,你会愿意做哪个?
所以,单纯代码行数来评估工作成绩的做法,肯定会让开发者变得挑剔。
为了解决这个问题,可以再将「业务复杂度」和「bug率」引进来综合考核就好。
给每个需要完成的功能做一个业务复杂度的评级,不同的级别对应不同的bug率,再将代码行数统计进去。
当然,这样做不单单需要开发者的工作,也包括测试人员的结果等等。
之前在某家市上公司任职时,我就是这样指定考核标准的。
对于KPI的问题,我知道大家都很讨厌。我也不喜欢KPI这样的东西限定程序员,但大公司一般都如此,没办法的。
这个是个老生常谈的话题,tiny提到那个没有函数,只是copy/paste复用代码的个例实在太极端了,也许我真还没见过那么蠢的“程序猿”(如果这样也能叫程序猿的话),我是没这种耐心教育如此极端的个例的,当然我也没做过咨询类工作,也许这类工作的要求本身就必须得有这么高耐心。但潜意识里缺少“模块化思维”(我把一切复用方式都笼统称为模块化,无论是库、包、类、方法/函数)的程序猿确实不少,系统架构设计定下来后让他理解他能理解“模块化”,但让他自己单独处理局部问题和局部之间的关系的时候就能发现他潜意识里缺少模块化思维方式。我实在不理解为什么那么多人会觉得copy/paste是一种“高效”的方法,我自己倒是偏极端的反例,看到任何近似逻辑的部分都有洁癖想去把它整理成共用的部分,很多时候我倒是很需要压抑自己这种洁癖,尽量不要去过分完美代码,除非的确需要(例如发现重复三次或类似需求有三处以上)。
另外一方面,我认为在一个人对一项技术以及所应用的领域比较熟悉的情况下,写代码的过程其实不是特别需要用脑的,几乎是超过50%在机械化工作,因为你很熟悉面临类似问题所需要采取的解决手段,甚至自己已经形成一种比较固定的模式,这种模式帮助你快速编写代码(包括已经很习惯而且非常固定的编码范式)以及自动避免了常见容易出现的代码漏洞和陷阱。真正花时间的地方在于架构设计层面以及一些局部的接口设计方面。到这种程度,我觉得代码行数才能比较直接反应工作量。否则任何涉及设计以及解决某个不熟悉甚至为接触过的问题的策略时,所需要的时间和工作量通常是不太可控的。
还有一方面是看你所依赖的框架。像PHP,如果不依赖任何框架,代码量肯定比基于一个设计良好的框架大很多。
先看是否满足需求,再看质量/效果。
我重写过n个大系统,最近改的一个,原来大概12万行代码,我重写后变成2万多行,性能暴升,用户界面体验等全面提升。
代码行多只能说明你敲的代码多或者快,代码数量<>代码质量。
如果能用过更少代码实现更好的产品,那才是好代码。
前年就看过 Git 的用法,但是一直没用,看 Git 教程可以 commit 上去,但是不知道真正应该怎么用。
现在是用 SVN 到自己的Google Code.
就是这样...
这个问题可以借鉴工厂里的工时数。工人的工资都包含哪些就不细说了,其中一个项目就是和工时数挂钩的——例如,你每个月必须完成300工时,否则扣钱,超额完成的有奖励。我们不讨论这种制度是否合理,但它却能真实的反映出工人的产出情况。工时是如何计算的呢?它是一个虚拟的计量单位,当来了一个任务需要加工时,由工程师负责设计,工艺师负责工艺的规划(先干什么后干什么)——例如:这个件需要先铸造,再车、钳、铣、刨等工序。然后再根据经验给每一个步骤定出工时。定工时很有学问,因为它是跟钱挂钩的,所以你定的一定要合理。就如前面所说,如果你一个月内必须完成300工时,在任务量足够的情况下,不加班一个月工作大约22x8=176小时,也就是说你要在176小时内完成300工时的工作量。再回到工时的合理性上,定工时必须是正常情况下工人工作176小时可以获得300工时,而且还要考虑下面的诸多问题:
更要考虑成本的因素等等……
总之,你定少了工人不干,你定多了领导不干(成本控制)。从未接触过的任务则是先根据经验定一个,生产中发现了问题再调整。另外,如果实际生产中因为个人原因出现不合格产品,就要扣相应的工时。
同理,在软件项目中系统架构师当然是工程师的角色,项目经理应该是工艺师的角色,然后确定每个模块、任务的工作量。软件工程里习惯用人*日来表示工作量,如果一个任务定了是3人日的工作量,你1天干完了就赚了,你5天干完了就赔了。你觉得工作量定的不合理可以和项目经理讨价还价。
之所以举这个例子,是因为我觉得两个工作很有相通之处:每个任务都需要技术、经验和智慧,同样一个工作,不同的人会有不同的结果,只要是产出合乎质量要求,就应一视同仁。