如何提高自己的代码/工程能力

代码能力是计算机学生必须具备的能力,但简单地说”代码能力“是不够的。项目需求、程序设计语言、开发框架多种多样,能力必须有针对性地培养。代码能力粗略地分为两类:写出(高效)解决单个问题的代码的能力,即算法能力,和写出整体高性能可维护”优雅“的代码的能力,即工程能力。这两者都可以继续分类,但一来篇幅有限,二来笔者也不能面面精通,就简单地这么分了。

基础工具和能力

在讨论代码能力之前,先简单介绍算法题的训练方法和开发工具,这些都是必要的。

算法题

关于是否要大量刷算法题历来颇有争议。有人说数据结构很实用,说算法能锻炼思维和在压力环境下解决问题的能力,但也有人说算法题需要大量重复训练单个知识点,学到的很多算法和实际应用不符。笔者所学所用还不足以判断两种说法的正误,但是,不管是申请实验室还是找工作,算法题是笔试中的常客,一定程度上是选拔人才的标准。所以,即使不从纯粹的学术角度或者工程角度出发,在刚进入大学的时候,多刷算法题还是对自己的发展还是很有帮助的。

如果是刚刚入坑计软网的小白,首先推荐去洛谷或者 AcWing 的题单,把官方题单刷一遍。刚开始刷题时,即使自己完成了,也要看题解中是否有更优秀的方案(一般是没有,leetcode 这种时间卡得松的会有);如果独立完成不了,思考最多 10 分钟,去把题解看懂,不要觉得气馁,因为很多题目都需要特定的数据结构和算法,只是没学过而已。

一般需要掌握以下内容:

  • 基础:程序控制语句、数组、指针、函数
  • 基础算法:排序、穷举、贪心,等
  • 数据结构:链表、二叉树、图,等
  • 图论:搜索、最短路、连通性、连通分量
  • 询问:区间最值、单点修改区间维护、区间修改区间维护,以及各种变种
  • 动态规划与记忆化搜索
  • 数论(密码学)
  • 数值计算(较少)
  • 计算几何
  • 等等

熟练掌握了这些(大概 500~1000 道题的训练),你应该能通过一般的笔试了。如果做不到,也没关系,按照自己的安排有选择地完成一些也可以。如果你想参加 ICPC 等专业性程序设计竞赛,需要更加大量的训练,比如在 AtCoderCodeForces 进行 Virtual Participation,并积极参加校 ACM 集训队的选拔和训练。

开发工具

虽然软件源代码一般都是文本文件,但合适的工具能够提供文件大纲、代码重构、实时检查等让开发效率大大提高的功能。下面推荐一些比较常用的编辑器和集成开发环境(Integrated Development Environment,IDE):

  • IntelliJ IDEA:强大且全面的Java IDE,JetBrains 公司开发。分为 Community 和 Ultimate 版本。Community 为纯 Java IDE,Ultimate 提供了 Python、JavaScript、Go、数据库等支持。其它主流语言也有配套的 IDE 支持;JetBrains 提供了 CLionRider 等针对其他语言的 IDE。
  • Visual StudioWindows 下最强调试器,微软开发。提供很棒的 C#C++ 开发体验。同时可以提供 Python、Node.js 等的支持。
  • Visual Studio Code:轻量级编辑器,微软开发。其以强大的插件体系,基于 Language Server Provider 的语法提示,以及优雅的界面和快捷键操作而广受好评。

学习开源代码

优秀开源代码是很好的学习资源,在代码里可以学到从设计到每个部分的具体实现,如果能读完一套相关领域优秀框架的源码,作一份笔记,将对自己的能力有很大帮助。

针对性学习

同样是代码,不同的方向,从思维模式到常用框架都大相径庭。这里以 AI 科研和互联网技术两个方向分别作为算法能力和工程能力的代表,简要介绍如何针对性学习,而更广泛的领域还需要读者发挥自己的主观能动性去探索,并与有经验的前辈交流。

AI 科研方向

AI 科研方向的编码和工程方向差距很大。首先是语言上的。目前 AI 的科研主要使用 Python 语言,语法灵活但工程性一般。其次是目的上的。AI 的科研代码不追求高并发等极致的性能,而是通过数学推导或者实验得到一个算法后进行实现,证明这个方法work,能够达到 State-of-the-art 的水平即可。最后是维护上的。论文的算法代码一般不需要维护,作为 demo 即可,而工程代码需要随着 bug 的发现、需求的增加与变更、人员的变动等进行维护,所以工程代码的可读性、可维护性要求更高。

最常用的深度学习框架是 PyTorch,互联网上有很多如 https://d2l.ai/ 的教学网站,Manning 出版社的 Deep Learning with PyTorch 也是非常好的教材,但这远远不够。真正的锻炼应该发生在实际的科研或项目中。所以在学完基础知识之后,通过阅读参考文献的源代码或者知名开源工具包,自己复现,能很好地锻炼代码能力。

互联网技术

互联网“寒冬”不知道是快要过去还是刚刚开始,但是可见的是,软件能够提高各行各业的效率,所以软件工程师的需求还是很大的。虽然笔者没有选择就业,但可以体会到的是本科毕业进“大厂”的难度不亚于保研、考研,所以如果对工程更感兴趣可以提前了解、准备。

针对传统的前后端开发,可以分为 Web 前端方向、移动端方向、后端方向、数据分析方向等。

  • Web 前端方向主要是基于 HTMLCSSJavaScript 构建在浏览器中运行的页面。目前有 ReactAngularVue.js 等框架,WebpackVite 等工程化工具,TypeScript 等类型安全的 JavaScript 变体。
  • 移动端方向主要是基于 AndroidiOS 等基于操作系统的应用开发,也包括使用 FlutterReact Native 的跨平台开发模式。
  • 后端主要是基于 JavaGoC++ 等语言,使用 SpringDjangoFlaskGin 等框架,使用 MySQLRedisMongoDB 等数据库,使用 gPRCDubbo 等远程过程调用技术开发向前端通过网络提供数据服务的应用,因为涉及的知识太过繁杂所以不展开了。
  • 大数据方向主要进行海量数据的存储、处理,通常与知识挖掘等联系起来。主要使用 Spark 等工具。

对于这些方向的学习,首先应该有一本详细的教材,比如对于 JavaScript,可以考虑红宝书《JavaScript 高级程序设计》或者犀牛书《JavaScript 权威指南》,由浅入深地学习。然后通过实际项目进行练习,跟着教程做一个网站等。最后是在实际项目中学习,比如在公司实习、对学校某处进行信息化改造、参与开源项目等。

注意,以上都是很浅的介绍。而更多的,比如嵌入式、机器人、区块链、图形学、高性能计算等,也都有专门的学习内容,如果对某个方面感兴趣,可以通过实际项目针对性地深入学习。

模块化

在 LeetCode 或者其他平台刷算法题相比写项目而言是快乐的——

  • 单元性:一个问题只有一个关注点
  • 零成本试错:百余行,大不了从头来过
  • 充分的测试:使用精心构造的测试样例来保证程序的正确性
  • 即时反馈:提交题目立刻得到反馈,正确了就过,不正确也能知道是哪个样例错了

但工程项目往往是一个高度复杂的系统,而一个人能记住的代码是有限的。模块化可以将一个大的系统分解成若干个小的模块,每个模块遵循”高内聚、低耦合“的原则,各模块之间的接口是简单而相对固定的,模块内可以比较自由地编码。

多人合作项目,或者需要长期维护的项目,有必要写好设计文档和 public API 的代码注释。推荐使用 Unified Modeling Language (UML) 来进行建模,绘制 UML 图的方法有很多,可以使用 Visio,也可以用 Mermaid.js 等文本绘图工具。

设计模式也非常重要,合理使用设计模式可以使代码更加整洁、可维护:如果你说”这段代码使用了策略模式“,其他维护者能够很快地理解你的意图。传统的 23 种设计模式分三大类:五种创建型模式,七种结构型模式,十一种行为型模式。设计模式出自 Design Patterns: Elements of Reusable Object-Oriented Software 一书,但书中示例比较老了,Head First Design Patterns 以比较生动的方式讲解了一部分设计模式,也可以通过其他资料学习。

行动起来

代码能力的特点在于勤能补拙、熟能生巧。只有经历过足够多代码的历练,才能成就一名优秀的程序员,之后才能成为工程师、创业者、科学家等。

如果是工程方向,可以做几个实际项目,可以是自己想做的东西,可以是仿造市面上一个流行软件,也可以来自其他人的需求或者外包;

如果是科研方向,可以参与导师的项目,也可以自己组队完成感兴趣的课题。

培养读官方文档和源码的能力

不论是什么项目,在深入学习一段时间之后,就会发现:”百度一下“能找到的东西太有限了。很多知识都存在于官方文档中,甚至为了明白到底发生着什么需要直接进入所引用模块的源码。通过阅读文档/源码,可以学习如何严谨地设计程序的结构,以提高程序的各项性能。

results matching ""

    No results matching ""