一、问题
问:对于C++,该如何才算一个合格的初级开发工程师该有的水平呢?比如,应该优先掌握哪些知识点?
二、南老师高赞回答
1. 基本方法
摸清用人单位是怎么用C++初级开发工程师,可以反过来知道初级开发工程师应该掌握哪些知识点,到达什么水平了。
这篇回答显然也广泛适用于 “该如何才算一个合格的初级(软件)开发工程师该有的水平呢?”这样一个问题。不过,既然问题强调“对于C++”,所以我会在不少地方指出,当语言是C++时的特殊之处。
2. 边界设定
咱们先划好两个边界:
1.用人单位是指什么用人单位?
大厂招C++怕是不可能招C++新手的;所以下面谈的“用人单位”指普通的软件研发公司,大概就是研发人员在10到500人左右的公司,都有机会。
2.初级开发工程师,得是多初级?
我们就定位在:来企业参加实习的,大三或大四阶段的计算机相关专业的,并且被国内几个大厂筛选过一遍的学生。
3. 用人场景模拟
我们设定为:在一个人员规模为十人上下的团队里,通常用人单位怎么用这个实习生?
刚才提用人单位可能也不算小,上限都随意切在500号开发人员。不过新人进入的项目团队,通常也就10人(含前端、测试,不含美工)左右的小团队。
这个小团队里,还得有数位C++开发人员。依据C++在国内的主要应用方向,应该有三种典型的业务范畴:
- 一种是使用C++开发服务器后端。
- 二种是原生桌面GUI开发(这里的原生放宽了些,不一定非要原生OS的API开发,Qt也算)。
- 嵌入式(包括物联网)的特定应用。
下面我们就围绕企业最可能的用人方式(反过来讲就是你的工作方式),分别讲讲你需要优先学习哪些C++知识点,以及应该学到大概怎样的水平。
4. 算法岗位
4.1 推导
好,先给出第一种相对稳定知识结构与用人方法推导:
if ( 从事第1或第2种应用范畴
&& 新人算法、数据结构不错
&& 团队技术负责人的算法、数据结构更/也不错 ) {
新人会被安排为使用非常基础的 C++ 语法帮助实现(甚至设计)项目中需要的算法
}
如果你C++自身水平不算太好,但算法(自然就包括数据结构)成绩还算不错,并且你觉得先有份工作站稳就好; 那么在参加面试,不凡反向观察一下:可能从事的项目是否比较需要算法、面试的技术官员及未来的直接主管是不是算法牛人。
这三个条件缺一不可,特别是条件3。遇上那种提算法就蛋疼的技术主管,那就没法子了。
好,这个用人方式及相关条件下,你只要算法数据结构好,就相当合格了,且极大可能日子过得比好多同学爽,并且较早赢得一段自己边干活边补充或继续提升C++语言技能的时间。
很多高中玩过奥赛的同学,这个方式就是你们额外的捡来的,可以考虑下。
关于这一点的重大提醒是:切记切记!在项目中用算法和你在校玩的算法参赛有很大不同!你仍然需要充分理解业务需求,然后把算法应用到某些业务逻辑 、业务流程中去。不了解需求,你的算法能力可能会没有用武之地。
4.2 C++在算法岗的特殊处
由于C++更常用于开发一个系统中相对底层或中间层的支撑,以及相对比较在意性能的模块,再加上C++经由STL及其超强泛型支持达成的一流的抽象表达能力的同时,仍然具备相对有保障的性能支持,所以很多核心算法会交给C++实现。所以,在其它因素相近的情况下,技术团队往往对C++程序员的算法能力有更多的期待。
事实上也不仅仅是期待,出于某个原因,国内很多在初高中就开练的刷题人(中性词),也是从C++开始的。所以,结论就是:对于学C++的同学,你要是算法超过多数人——但你的C++语言、以及系统层面的知识(操作系统、网络、数据库)又暂时一般(所以你没能进大厂),那这第一种用人方式很可能会直接砸在你头上。
4.3 初级算法岗需要掌握技能点
如果你想往这个方向靠,那么要掌握哪些算法数据结构才能达前述背景下的“初级”要求呢?
- 你还是要掌握C++语言以及计算机的一些本质原理。所谓的算法是要实施在C++这门语言之上,因此算法的复杂度若仅停争为在大O表达是很不够的。你得对C++的栈分配、堆分配、传值、传址、以及C++有的“移动”或特定数据结构,比如string-view等有基本的了解——这些是更合适归入语言,但其实是算法具体实现的极度依赖的技术细节,要深入的懂(面试问不倒),下面涉及到锁问题也是如此。本质上是结合具体实现的复杂度(时间、空间)分析。
- 线性表的种种(一):单向、双向、循环以及并发下的加锁处理带来的影响,如何在能得到正确结果下的减少加锁的颗粒度等等……
- 线性表的种种(二):你不仅要会使用STL里那套非侵入式实现的使用,还得会C方式的侵入式的实现。注意,就是要会用C++/STL现成的,还要会用C方式实现。你可能会说我明明面试的C++的岗位啊——不是啦,你面试的是其实是算法岗位。STL虽然是极其牛叉的设计,但就以线性表,C的实现在许多场合下需要性能远超std::list。表面上这是一个设计方式不同,但其实是一个算法问题。
- 散列表的种种……要懂原因,会实现(还是指C方式的实现)
- 树的种种……二叉查找、平衡、完全、多路查找下B、B+、堆(大小顶、优秀队列等)……要知道它们的特点,适用场景,最后还要会用C写;
- 图的种种:有向无向、关键路径、这个在多数业务场景下,要求可以低一点,知道原理、理论即可。当然,不保障你要去的公司的业务,正好就是强烈需要图的相关知识也未必。
- 排序:冒泡、插入、选择、希尔、归并、快速、堆排。以及如何实现部分排序、还有稳定不稳定什么的……你都要懂并且会写。当然,此时的考核重心已经从数据结构偏向算法,正常是允许你用上C++及其STL来实现;另外,作为更低要求,你当然得清楚STL在这方面现成的东西,比如STL中哪个是现成的部分排序?
- 排列组合:这个高中知识吧,实际工作中大量使用,这个原理就是高中书上的,估计没人会直接问你。主要还是针对某个实际问题,结合STL使用。比如STL中有现成的全排列算法,你得知道……
- 查找/搜索:深度优先、广度优先什么的,通常结合数据结构的结合应用。
初级的话,大概这些吧——这是按应用度我粗暴切出来的。特定企业的特性要求当然会造成切的位置不同。
5. 验证或预研岗位
5.1 推导
如果你上岗后不久,领导交给你某个工作,并且这个工作有一个典型的技术管理上的特征(细节),那么你的领导可能就是在采取这种方式在使用你。这个技术管理细节就是:
你被要求先在一个独立的,往往是临时工程(Project)写代码;你的代码现在不是,并且往往最终也不会完全进入最终项目的代码树里,那你很可能就是在做验证或预研性质的研发工作。
- 最好的情况:技术主管欣然以你的代码为项目原型,直接在上面开发最终项目的代码树;
- 好一点的话:你的部分预研代码会在审核通过后被纳用,进入最终项目的代码库;
- 还好的情况:你的验证或预研结果被采纳,但代码太烂被无视,被抛弃;
- 算你有功的:你的验证或预研结果是正确的,不幸的是验证或研究结果正好证明了这个方向是错的,你为个项目发挥了试错的作用,也算你有功能和一份贡献;
- 准备走人的:你的验证或预研结果让技术主管大吃一惊,他看了看你的代码,当天他就独自留下来加班,并且第二天有人通知你:你的验证或预研过程错得离谱……
企业对C++新人这种使用方式应该是非常普遍的,特别是在项目初始阶段。其中的“验证”和“预研”既相近,但也有不小的区别。
- 验证工作:上司对某个事物有一个基本的,甚至相对确切的判断,但出于技术工作上的严谨,需要有人去具体的验证一把,得出确切结论及详细的实验数据。
- 预研工作:上司对某个事物尚未有一个基本判断,需要你去在预先研究以得出结论
注意,参与第一类工作(算法)的新人,也有极大可能同时参与本类工作;因此这类工作的典型案例,我们至少还得再加一条:
- 已知数量的数据处理,在某一种或某几种算法下的基本性能表现等。
5.2 C++在验证或预研岗的特殊处
标准库中,线程、正则等11年才进入,网络没有(听说要2023年?哦,今年已经是23年了,现在看得26年了!),日志库没有,JSON处理?XML处理?标准库封装得极其的薄(标准库严重地偏好形而上的抽象层)。这是C++的特点。这个C++的典型特点——当你要开发重业务类型的实际项目时,很多时候会视此为弱点——带给C++初级工程师的“好处”就是:以C++语言为开发主体的项目在真正破土动工之前,需要预研或验证的工作,还真是比其他语言多得多。比如前面提到的:需要处理JSON数据——这太常见了吧——大多数主流语言都是标准库自带,或者标准库没有但有约定成俗的首选第三方。到C++这儿……github上一找好多啊,用哪个呢?再如MySQL连接、再如Redis连接、再如ORM、……
“感谢”“不食人间烟火”的C++标准库给C++项目带来到这么丰富的前期工作内容。并且这些前期工作中的前期工作,经常会落在C++新人工作任务清单上。为什么呢?就不怕新人搞不定吗?不怕的,因为这类工作虽然听起来很高大上“验证”甚至“预研”……但其实工作实质是“使用一个个现成的库” (其实很重要!)。C++的多数基础功能想实现成一个正确的、通用的、高性能的、稳定的,并且保持良好的易用性的库、都非常具有挑战性——但是一旦大牛把这个库做出来了,通常C++编程小白就能够在一番折腾后,把它们用起来。
5.3 验证、预研岗需要掌握技能点
现在,我们自然是要谈谈:假设我算法能力一般,但我还是挺想找个C++的开发工作,于是我想先从参与这类预研、验证性质的工作做起、做好。我应该如何努力呢?
- 你还是要掌握C++语言以及计算机的一些核心原理。因为这是前面分析结论中那句“通常C++编程小白就能够在一番折腾后,把它们(第三方库)用起来”的前提假设——所有“库”级别的产品,都是建立在它的使用者是身怀C++基本功的这样一个假设。这里的"基本功",不同前辈对C++新人会有不同指导及评判方法。对我来说,就是你搞定我的《白话C++》练功篇 。
- 然后你要有干杂活的动手能力,下载啊、配置啊、编译各类库(并且这里要特别强调开源库,因开源库往往很难为你提供手把手的服务及指导)。避免在工作岗位上阴沟里翻。《白话C++》第2章"准备",你试试。光看书就能搞定,你的动手能力很有保障; 搞不定就看我网站的配套视频——如果还是不行……我个人意见是:算了。
- 学习技能的能力。
不同的项目需要用到的第三方库通常各不相同,那我们要怎么在面试过程中,让面试官知道他想要找的“虽然是新人,但动手能力、学习能力强”的人,就是眼前的你呢?
显然,这事就看你在学习过程中,已经实际搞过及搞定多少第三库嘛。并且,你搞过的库越有知名度,越有适用性,就越能让面试官相信你嘛。作为反例,假如你提了十个库,结果都是非常小众的,面试官一个都没听过——你觉得效果会好吗?恐怕都不到找不到相同话题。
5.4 建议优先考虑学习第三方库
我就从网上(主要是github)上,给大家列举几个库,想找到C++初级开发工程师的人,可以一个个去攻克下。注意,相比你在网上搜索得到的什么 “C++库大全”,下面这份清单一是时效性强(你找到的C++库清单中间往往有一堆是停滞不维护且技术落后的东西,很难在融入现代C++项目),二是针对性更强(难度适当,适于新手学习;且有知名度、适用广,面试有利)。
这些库有C++也有C的——这在实际项目中再正常不过了,这是特性、优点,不是缺陷。
- JSON:nlohmann/json
- XML: tinyxml2
- 日志: spdlog
- 单元测试: Catch2
- GUI: (1): nana (2): wxWidgets 这一项这个要特殊说明:由于GUI是一个非常庞大的体系,所以如果你在面试已经较为完整地学习更有适用面的Qt,那当然很好;但如果没有,可是你又想三个月或半年就想去面试,那你学习Qt恐怕时间精力上来不及。这时你学习nana,wxwidgetes,时间是来得及的,并且正常的面试官会相信你具备搞定Qt的学习与动手能力
- 网络客户端:libcurl 以及第三方的C++封装 curlpp ;最好你自己能用C++做一些简单封装;
- 图形处理:CImg。重点就是用,比如能用它生成网站登录常用的“图形验证码”; ImageMagick 也建议学习,然后可以用它搞一些效果(比如单色化呀,生成油画风格啊)。注意,重点是使用,但最好能懂此图形处理的算法原理,最基础的比如:RGB颜色的表达,图像透明的基本原理等。
- redis 库:你当然得先学习Redis;然后会用C++程序去读写(比如:redisclient),最好包括批量读写的实现。
- mysql库:同上,你当然得先学习mysql(SQL),然后会用Oracle官方提供 mysqlclient库,以及Oracle 提供的那个老版的 libmysqlpp (链接我不给了,名字也可能不对,可上oracle的mysql官网搜索)。也可以试试历史悠久但一直在发展现的 libmysql++ 。如果你C++模板还有点基础,可以学习一下很现代的 sqlpp11。
- MQ: zeromq的 libzmq 或 cppmq 。这项的学习重点是除了会用消息队列,更主要的还是借此知道MQ的基本概念、应用场景等。
- 并行计算:cpp-taskflow 。
- 小型游戏:libsdl2。它也有 c++封装: sdl2pp。
- 加密: openssl 库
- C++准标准库 boost 的涉略:boost.uuid, boost.utility, boost.format, base64. datetime, 命令行参数处理……。
6. “打杂”岗位
打杂是加引号的,严格讲,就是参加大量相对基础的,功能性的“工具代码”编写。
这类的C++新人使用,有那么一点点夹在“方式一(算法)" 和 "方式二(验证,预研)"之间的意思。不过,我想用一个听起不太好的词来表达:打杂式的开发工作。展开说,就是让你开发一些基本功能函数。这类功能实现可以理解为一些相对通用并且简单的算法。比如:去除字符串的前后空白——你可以使用for循环硬写,也可以是对boost库里现成方法的二次封装等。这类工作的典型的特征有三个:
- 基本最后是要进入最终项目的代码树的(除非你写太难,通不过代码审查);
- 你的上司要求你一定要写好单元测试,并且你写起来功能测试来也感觉非常简单。
- 如果你写错了,通常很快就会接受到上层使用者的不满情绪…… :(
如果第2点你不好好干,通常才会落到第3点。无论如何,这类代码虽然本质上很重要,但你的上司却敢于让你这位新人去写……
写挺长了。这类工作的其它注意点,大家就暂综合前面两点来思考吧。
三、更多建议
单独列为一点,以示其重要性。
建议广大C++初学者,在提高动手能力的过程,能优先考虑为自己准备一台 Linux 的C++开发/学习设备(台式机,笔记本都可以,内存至少16G,建议24G,可能的话直接上32G)。上面的那些库,都兼容Windows或Linux;但在Linux下,会给你带来以下三点好处:
- 通常安装这些库更方便。极大减少这方面时间的浪费;
- 更大概率接近你未来从事C++开发的实际环境:Linux下的服务端开发。当然,如果是桌面应用的话,那还是Windows更有可能;
- 敢于脱离熟悉的windows,会在linux下开发,也增加了你动手与学习能力。