一个程序员的学习成长之路

这是一篇回忆性的学习经验总结,从笔者zt(现为小米有品高级软件研发工程师,主要负责iOS客户端与跨端开发的基础建设)自身移动客户端开发的经历中提炼而来,力求提供一个平台、语言无关的视角,分享一些学习经验。

在工作中学习 —— 一切从实际出发

初出 茅庐

刚开始实习工作的时候,我也是一个萌新,什么都不懂,也是从读代码、改bug起步 —— 当时甚至无法分辨什么样的代码是好代码,什么样的代码是“有问题的”(即使它可以正常工作)。在改bug的过程中,我逐渐熟悉了整个项目的结构,对开发的语言也更加熟练了,导师就逐渐开始给我分配业务需求。此时的我尚处于依葫芦画瓢阶段 —— 参考项目中别人的代码,然后模仿着写,以达到我的工作需要。

Effective 系列书籍  ——  “最佳实践”

在初步学习语法,能实现简单需求后,我进一步阅读了对应的 Effective 系列书籍(例如 Java 对应《Effective Java》、Objective-C 对应《Effective Objective-C 2.0》)。书中罗列了前人总结的技巧和经验,阅读时仿佛是作者(一般也是资深程序员)在手把手教我写代码、解释特定写法的具体原因。我从中受益良多,逐步提高了代码质量和编程水平。

该系列是实践的总结,很容易运用到日常工作中。书中可能有部分章节暂时无法理解(例如尚未接触的语言特性),可以看个大概留个印象就跳过,随着编码经验的积累、熟练度的增加,过段时间再阅读可能就理解了 —— 温故知新。

注:一门编程语言自发明、普及之日起,就有无数前人、同行在实践中探索,随着时间和经验的积累,沉淀为一套适合该语言的 “最佳实践”,其中有些是语言无关的,有些是与语言特性强相关的。需要强调的是,“最佳实践”不是金科玉律、万能公式或银弹,只是在大多数场景下经过实践检验所总结的“温馨提示”,偶尔失效的时候具体情况具体分析即可。

思维修炼 —— 重构与设计模式

随着版本迭代、需求变更,逐渐发现有点力不从心,就算是改进一个功能,也改得很痛苦,有种牵一发而动全身的感觉,甚至可能导致了不相干的功能出现 bug,经常出现“需求本身的代码量不大,防止影响其他功能的代码量很大”。我意识到一定是哪里出了问题,不应该是这样的。

我向导师描述了我的困惑,他指出我的问题是“新手常见的问题,只着眼于局部的方案实现,缺少整体的方案设计”,建议我去学习重构和设计模式,分别用于“改善既有代码的设计”、“实现新功能时更有章法”。

重构:脚踏实地

重构方面,我只阅读了《重构:改善既有代码的设计》,虽然示例采用 Java 描述,但是不影响理解概念、运用,由于该书本身是比较偏实践的,因此可以边看边运用,看得也比较快,常用的重构手法实际操作一次就基本掌握了。

当然重构还涉及另一个问题:如何确保重构前后功能一致、不因此而引入新的 bug?常用的解决方式是使用单元测试,对于比较小的重构可以不做单元测试;某些场景下不方便做单元测试的,也一定要自己进行充分测试再提测、上线。

《重构:改善既有代码的设计》 第1版示例语言 Java,第2版示例语言 JavaScript
还有《代码整洁之道》、《代码整洁之道:程序员的职业素养》也可以了解一下

设计模式:高屋建瓴

设计模式方面,导师希望我能尽快阅读 《Head First Design Patterns》,这样他跟我沟通、交流时可以用更抽象的层次交流,而不是必须用具体实现指代,但是他也强调不要过度设计,看见什么就想套一个设计模式也不好。看完之后,我感觉一知半解,不知道如何使用,于是又看了其他几本设计模式的书《Design Patterns Explained: A New Perspective on Object Oriented Design》、《Design Patterns: Elements of Reusable Object-Oriented Software》、《Agile Principles, Patterns, and Practices in C#》,才稍微有点理解什么是设计模式、什么时候该用哪种设计模式…… 此后通过阅读项目源码,进一步确认自己对设计模式的理解没有出现偏差,并逐步掌握常见的几种模式。

实际上这些书也不用全部看一遍,看《Head First Design Patterns》,再结合项目代码、开源代码(和其他人的文章),在反复翻阅、对照中就可以逐渐理解了。

小结

重构与Effective系列一样,都是直接的技巧总结,实战性比较强,可以当工具书使用,随看随用;设计模式是大多数情况下设计层面的“最佳实践”,偏理论,阅读后还需要靠日常的积累、领悟才能掌握,是一个漫长的过程。

笔者个人认为重构与设计模式是比较好用的两个工具,值得花时间去学习与练习,用好这两个工具,可以使代码更优雅、易维护、可迁移(即使语言不同);但是过度使用设计模式会增加项目复杂度,反而不易维护,需要适度。

在学习过程中也会出现三个阶段:

1.不知道重构、设计模式是什么

2.看见代码就想重构、就想套用某种设计模式

3.正确思考何时进行重构、何时采用正确的设计模式

一言以蔽之,这两个工具可以不用,但最好学会使用;不鼓励到处使用,只在必要时使用

递归学习 —— 多问自己几个为什么

相对于业余时间学习,在工作中学习很明显的一个特点是,学习的时间是有限的 —— 毕竟工作任务是有排期的。在达到一定熟练度后,可能提前完成了工作任务,如何利用好这额外多出来的时间?我的习惯是,思考自己在本次需求中的代码是否有改进、重构空间,检验前期在不明朗的情况下做的一些假设,阅读、整理与这个需求相关的其他代码。

举例:商城app内某个首页楼层

以需求“实现某楼层”为例:

1. 参照其他已有楼层,模仿着写,按需求实现楼层效果,达到提测标准

2. 思考自己实现的代码是否可以改进、重构(重构经验不丰富、技巧不熟练的时候,或者功能复杂的时候,先实现功能再重构很重要)

3. 对于复杂需求,务必对关键步骤添加注释、撰写实现文档,以便后续维护

4. 思考自己实现的楼层到底是怎么被加载、渲染的,写的那些方法调用栈是怎样的

     a. 查看是否有其他同事已整理好的文档、图表(类图、流程图、时序图)等

     b. 如有,则结合文档、图表阅读源码,可以事半功倍

     c. 如无,则尽量在阅读源码过程中同步进行整理,方便将来的自己也方便他人

     d. 整理过程:

    i.梳理实现楼层时涉及到的类、接口(类图)
    ii.  梳理楼层本身是如何布局的,楼层间距是怎么实现的(流程图、时序图)
    iii. 梳理楼层是如何获取、加载、缓存数据的(流程图、时序图)
    iiii. 统计数据是如何收集、上报的
复制代码

5. 理清楼层本身后,可以进一步思考,点击楼层会触发页面跳转,那么页面跳转、路由是如何实现的?

    a. 页面如何注册?

    b. 页面如何跳转?

    c. 页面跳转的动效是如何做的?

6. 实现楼层时,使用的已封装好的组件是怎么实现的?

7. 有些楼层是动态化楼层,那又是如何实现的?

即,不仅仅停留在完成任务这一步,而是多问自己几个为什么,去探索、发掘背后的原理、方案。一方面可以更快地掌握整个项目的结构,另一方面也是通过阅读拓宽思路,互通有无。在梳理的过程中,配合画一些类图、时序图、流程图,可以更好地帮助自己理解,也方便以后快速回忆,而不用再从头翻代码,从而提高以后的工作效率。

上述示例,从实现一个楼层的需求开始,刨根问底,扩展出了一系列问题,这个扩展像递归一样(暂且称为“递归学习”),本身就成为一种“线索”(递归栈),有利于加深对整个项目的理解。从几个不同的需求或者功能点出发,按这种方式探索,就可以将这些“线索”组成网,从而掌握项目的全貌。在这个过程中,必然会伴随着 方法 -> 类 -> 功能模块 -> 应用分层 -> 整个应用 认知层次的变化,这种变化是可复用、可迁移的,适用于其他项目。

学习新知识点

有时实现需求的时候需要用到尚未掌握的知识点,例如字符串匹配要用到正则表达式、客服/售后消息存储要用到数据库等,此时也可以进行递归学习——当然,首先学习到满足工作需要,保质保量完成后再用剩余时间递归学习。

这里的“递归”泛指某知识点涉及到的其他未知知识点所构成的“已知-未知栈”,在学习时当然可以按“深度优先”、“广度优先”两种方式学习,选择符合自己的习惯即可。

例如正则表达式,学习过程可能是这样的:

1. 学习正则表达式的“语法”

2. 如何写一个满足工作需要的正则表达式

3. 完成工作需求、重构等,达到提测标准

4. 解决写正则表达式时的疑惑(某些写法的匹配结果为什么跟想的不一样)

5. 探索正则表达式的原理(形式语言与自动机理论)

暂停与继续递归

递归学习时可能发现有太多陌生内容,在排期紧迫的情况下会感觉压力巨大、烦躁,产生抵触、厌烦等消极心理,影响学习效率。此时可以先不急于深入学习,只学到刚好会用的程度,暂时不去探索那些未知领域,将那些未知的内容视为一个“库”,不关心其具体实现,只关心其“接口”的调用方式;同时将学习进度“存档”,待完成工作后/心情平复后,再继续逐个掌握,逐层递归。

停止递归

时间精力有限,不可能无限递归学习,如何确定停止点?我好奇心比较强,可能会一次性学到不想学、(数理基础不够)看不懂就停止,有时也可能只学一点就停。

一般地,可以按如下规则确定:

1. 每一层学习的时候力求完全理解、掌握

2. 如果可以理解、掌握超过8成,就可以继续下一层学习(一般越往下,理解、掌握的程度越低)

3. 不足8成,可以停止,对掌握的点做记录“存档”,学习其他的知识点

4. 随时间推移,可能理解加深了,从其他知识点上递归学习到此前的记录,再次复习,确认是否可以继续学习

在工作外学习:书到用时方恨少

重温/补充学习教材 —— 理论结合实际

计算机专业的同学上学时学过不少课程,但当时可能学得一知半解、死记硬背,甚至及格万岁;非计算机专业的则可能连相关教材都没翻过。尽管这些短期内都不影响工作,但长期而言,欠着的总是需要还的。

教材、经典书籍的好处在于建立系统、全面的知识体系,串联起方方面面的知识点,弥补递归学习时相对碎片的知识点获取,加速知识网络的形成。而有了工作经验的加持,比起上学时的一知半解,此时再看教材、经典书籍,必定有新收获。

就像上文正则表达式的例子,是从工作实际逐步向理论靠近的过程。在这个过程中会发现,编译原理的教材中早已有所涉及,此时就有一种“理论联系实际”的恍然大悟之感,既加深了对理论的印象,又提高了实践能力。

如果把日常工作中使用到的技巧比作武侠小说中的招式,那么计算机专业所涉及的教材就是内功——只修招式不修内功,容易变成花拳绣腿;只修内功不修招式,有劲使不出;内外兼修,才能发挥出最大威力。

书籍包括但不限于以下所列:

  • 组成原理
  • 操作系统
  • 数据结构和算法
  • 网络
  • 体系结构
  • 编译原理
  • 数据库系统
  • 数学(离散数学、线性代数、概率统计等)

这些书籍都需要整片的时间(至少有连续的1小时)去阅读、消化,适合周末、假期学习。

总结与致谢

本文记录了笔者阅读 Effective 系列书籍,在导师的指导下学习重构、设计模式,在日常工作中进行“递归学习”的一些心得体会,以及随着工作经验的增长,复习经典书籍产生的温故知新效果。

感谢您的阅读,希望本文对您有所启发。

感谢笔者的导师黎玉华(黎半仙)和其他同事们在这一路上的指导与帮助。

猜你喜欢

转载自juejin.im/post/7041368180790394910