四个月前,我从大连理工大学的软件工程专业毕业了,这也意味着我长达16年的校园生涯结束了。在这四年的学习和编码实践中,我认识了很多厉害的人,学到了很多有用的知识,也产生了许多感悟,趁着今年的1024程序员节这个机会和大家分享一下,毕竟上了班之后每天累得只想躺平,一点技术文章都不想写,只能写写水文了~考虑到笔者还只有3个月正式工作经验,在此之前一直都是学生,对业界了解不多,如果本文中出现谬误或想与笔者进一步探讨可发邮件至wc@mail.dawncraft.cc。
一.什么是工程
首先,我们先来谈谈什么是工程。
工程是指以某组设想的目标为依据,应用有关的科学知识和技术手段,通过有组织的一群人将某个(或某些)现有实体(自然的或人造的)转化为具有预期使用价值的人造产品过程。 ——百度百科
从百度百科的解释来看,工程就是将科学技术应用于实践中,产出能够造福人类的产品。但是其中有三个关键点是需要注意的,分别是“目标”、“有组织”、“产品”,目标对应着软件开发的需求,有组织对应着软件开发的方式方法,产品对应着软件开发最终交付的整套软件系统。在这三点上,软件工程与传统的工程有着根本上的区别,这也导致传统工程理论是不适用于软件工程的,在下面几节中,笔者会围绕这几点和大家讨论什么是软件工程以及软件工程的核心素养是什么。
二.什么是软件工程
如果将软件代入上文中所述的百度百科词条中,应该可以得到一个对于软件工程的很正确的定义,但如果这样的话,似乎软件工程和其他工程相比没有任何区别,那为什么程序员天天加班,周末也加班,这些APP还这么卡,这么难用,bug这么多呢。
其实,这涉及到软件开发的三个特点,分别是:
- 软件的需求是在不断变化的
- 加大人力投入不一定会相应地提高软件开发效率
- 编码是纯脑力活动,其物理成本几乎为0,且软件可以随意复制,分发几乎不需要任何成本
我们拿软件工程和传统工程行业做个对比来解释上述三个特点,就以笔者最喜欢举的软件行业和建筑行业的例子来说,因为他俩看起来很像,抛开需求和过程不谈,一个交付的产品是软件,另一个交付的产品是房子,但是因为软件有以上三个特点,他俩就完完全全不同了。
- 房子盖完之后就不可变了,顶多重新装修一下,但是软件交付之后还可以大改,甚至在保证功能不变的情况下还能完全推倒重来(重构)
- 两个人砌一面墙花的时间一定是一个人的一半,但是两个人一起开发软件所花费的时间可能是一个人的二倍,因为引入了沟通成本(以《人月神话》中的一个例子来说,项目经理向一个进度有风险的项目投入新人,则一定会导致项目延期,因为新人培训是需要老人去带的,这和新人水平没太大关系,再厉害的大佬进到新项目也需要一定时间熟悉和学习)
- 盖每栋房子都要花一样的钱,但是软件复制一份卖给客户是没有成本的,软件的成本只在于研发阶段发给程序员的工资(你可以杠说服务器和带宽难道不用钱吗,我只能说你说得对但是和盖房子花的钱比就是九牛一毛)
综上所述,可以看到软件工程和土木工程是有巨大差别的,其根本原因还是因为软件开发是纯脑力劳动。事实上,所有纯脑力劳动都有这些特点,但只有软件工程规模过于庞大从而有人去专门研究这一学科。
在上世纪6、70年代,计算机刚刚开始兴起的时候,那时候的程序都比较简单,大多都是为了单一用途而设计的,如银行、军事、科学计算等,一个或几个程序员就能完成一个程序的开发。但随着硬件的迅速发展,软件变得越来越复杂,功能越来越多,如今已经达到了英雄主义式的单打独斗无法完成一整个软件系统的程度了。这就必须引入科学的方式方法来管理整个软件开发流程,带领团队响应不断变化的需求,持续交付高质量的软件系统,这就是软件工程。
所以在笔者看来,软件工程包括广义的和狭义的两部分。广义上的软件工程和软件开发本身没有太多关系,它研究的是如何对接客户从而获得真正的需求、如何用科学的方式进行项目管理以及如何实现人与人之间的高效合作。具体体现就是需求分析、项目管理、敏捷开发、测试驱动开发、结对编程、DevOps这些方法,让软件开发从个人的小作坊式变成了有科学的正规的方法论支撑的大型开发活动。
光有了开发方法还不行,对于软件本身来说,因为软件的其中一个特点是需求变化频繁,那么软件就需要有频繁的变化,所以需要软件本身具有鲁棒性、可扩展性和可维护性。再具体点,就是软件的设计和架构,我们自己随手写的小软件和一个正经的完善的软件系统之间的差别就在这里。但是良好的软件设计不是光靠上课学习能学来的,必须通过大量的编码实践才能总结出来,才能知道什么是好的代码,什么是坏味道(不过根据笔者的工作经验来看所谓的大厂也是一群草台班子,真正完美的软件工程实践不存在,也不可能存在,大家都是trade off和tricks,但是作为优秀的软件开发工程师,我们应当追求完美)。
总而言之,依笔者之见,软件工程就是研究两个方面的,如何进行团队协作和如何让软件能够适应频繁的变化,最终生产出易于人类使用的软件产品。
三.软件工程专业人士的核心素养
最后,笔者还想谈谈软件开发工程师应该具备怎样的素养,因为进行软件开发的主体是人,那么人的水平很大程度上决定了软件的质量上限,软件工程的一些方法能够保证软件质量的下限,但是上限一定需要通过高水平的程序员才能提高,这也是为什么很多商业软件的代码质量实际上是不如一些开源软件的。
和大多数人的看法不同,尽管编码能力(例如写代码、写算法题)、逻辑思维甚至于英语水平都很重要,但是它们还不是核心素养,笔者认为核心素养只有以下三点:
1. 解决问题的能力
解决问题是程序员的最基本能力,笔者衡量解决问题能力的标准是不看过程,只看结果,无论是通过搜索引擎、问前辈、调试代码、用tricks绕过还是什么奇奇怪怪的办法,只要能解决出现的问题,都可以算进去。这种解决问题的能力是最容易培养的,一般来说经过4年本科教育的科班学生都应当一定程度上具备这种能力,至少会用搜索引擎搜和问别人,而不是束手无策。那么优秀程序员和普通程序员的区别在于能够解决前人从未遇到过的问题,例如在使用某库时出现问题,而这个问题在文档、各种搜索引擎甚至开源仓库的issues中都搜索不到,没有人遇到过,这时优秀的程序员可以通过阅读源码和调试来确定问题,甚至对于闭源库还能通过反汇编来进行分析,最终给出解决方案或者想方设法绕过这一问题,笔者就在近十年的从业生涯中遇到了无数这种问题,并想办法成功解决(尽管有些解决方案并不优雅)。
这种能力该如何提升呢,其实就是看的多了、学的多了、积累达到一定程度水到渠成的事情,毕竟计算机行业中很多东西都是可以共通的,学习的知识是可以迁移转化的。笔者就是在初中的时候写Minecraft Mod的时候逐渐锻炼自己的问题解决能力的,那时候Minecraft还很简陋,很多代码都没有反混淆,Forge提供的接口也不完善,更没有mixin这种技术,不仅要读一堆混淆过的屎山代码,而且要进一步修改游戏逻辑还需要用asm库动态修改jvm字节码,这个过程就帮助笔者初步建立起了解决问题的能力,为后续软件工程能力打下了坚实的基础(毕竟能看懂mc那一坨之后,看什么代码库都不会觉得难了)。
2. 抽象能力
抽象能力是决定一个程序员水平上限的根本能力,抽象其实就是对现实事物提取最本质、共同的特征,然后在计算机中实现它。最基本的抽象是面向对象设计,例如is-a、has-a这种继承和组合关系,再进阶一点就是各种设计模式,再往上则是各种软件系统的架构。但笔者衡量抽象能力并非衡量会用多少种设计模式,会某某架构,而是在对一个新事物有基本的了解后是否能迅速总结出其特征,建立抽象层次,毕竟这些东西都能从课本中学到,但能随心所欲地运用于实际工程中才是能力的体现。
抽象能力的提升主要靠多读代码、多写代码、多总结经验。得益于阅读Minecraft源码的经验,笔者曾在初中还没有学习过设计模式,甚至完全不知道设计模式是什么的时候就已经总结出多种设计模式(其实设计模式就是这么总结出来的,只不过三人组比我早出生个几十年而已),并将其灵活运用于项目中,如今回过头来看当初写的代码才意识到这是xx设计模式。如今经过了近十年的编程实践,笔者已经能够在了解新事物后凭借本能就给出其抽象设计,不需要刻意去想什么面向对象、什么设计模式(但架构方面还需要积累),这便是抽象能力的体现,也希望大家通过学习也能够获得这种能力。
3. 沟通合作能力
沟通合作能力是当代程序员最重要的能力,前文的分析中已经提到当今的软件系统已经庞大复杂到单打独斗难以开发完成的程度,所以团队协作是必不可少的。更何况项目规模越大,人越多,沟通所花费的时间占比也就越大,这就更需要我们提高沟通能力,增加沟通效率。那么无论是拉通对齐、写文档甚至是写代码,这些都能体现沟通能力,要让对方明白你在说什么、能够理解对方在说什么,是十分重要的(这里有个小技巧,笔者喜欢先听对方描述一遍这件事情,然后再用自己的理解复述一遍,对方再进行补充,在这个过程中就能够迅速对齐,效率非常高)。而且依照笔者的观点,代码永远是写给人看的,优化是编译器该考虑的事情(除非你在写汇编),所以代码写的简洁易懂、注释恰到好处,这也是表达能力的一种体现。
当然,以上3点能力并不只是天赋,而是完全可以通过后天训练得来的,但是要想成为顶尖程序员毫无疑问是需要天赋的。笔者曾在高中时通过自己的探索逐渐发现了自己在1、2两点上是具备一点天赋的,所以在填报志愿时将计算机相关专业放在了前面,但由于过去完全是自己一个人探索,没有和行业内的人沟通过,更没有老师指导,导致笔者走了不少弯路,直到大二时才真正算是入门了软件工程,再加上平时课程和与同学的饭局中交流的感悟,进而有了今天这篇文章。所以,笔者对因为听说计算机行业高薪而慕名报名计算机专业的同学们有话要说,如果你在大学里学了四年还不喜欢编程,或是没有感受到自己有上面三种天赋中的至少一个,抑或是家里并不那么缺钱,不急于通过上班来赚钱补贴家里(注意是选其一的关系),那么并不建议你从事软件行业相关工作,可以转非研发(行政岗),或者读研、考公、出国都可以,否则参加工作之后只会怀疑人生,尤其是互联网大厂,压力会非常大。
四.浅谈我国软件工程专业本科教育
因此,为推进大连理工大学OurEDA实验室软件工程能力建设,笔者推出了一系列教程,旨在抛弃掉书本上无用的长篇大论,聚焦于实战用到的知识,欢迎大家学习:(虽然现在还只是新建文件夹阶段,只有个目录,后续会慢慢写)https://zvcdzitr772.feishu.cn/wiki/X7TiwGPhtiVIQDkk3ATcKNgnnMh。
五. 谈谈自己
笔者常认为学习编程就像是登山,但是是一座波浪起伏的山,
登不动了以后有空再接着写。。。