前端职业规划 - 作为前端该如何学好数据结构与算法

1,723 阅读10分钟

前言

现在几乎所有的程序员都知道数据结构和算法对于程序设计的重要性, 我们也奉 "程序 = 数据结构 + 算法" 为圣经, 社区里目前也掀起了一股算法热, 顺带也提升了设计模式, 数据结构等的关注度, 但大多数聚焦的点还是在于如何解题, 把算法和数据结构当成是一门考试在应对, 我们都知道, 一门技术如果不是兴趣驱动, 并且持续的获得成就感是很难真的有较大成就的, 就好像考试考过之后若干年, 昔年的知识也早已还给老师, 作为程序员, 想真正不断提高自己的程序设计能力, 对于数据结构和算法还是应该以兴趣来驱动, 并且能将其应用到实际工作中解决问题, 通过解决问题获得成就感然后进一步驱动自己深入去学习和掌握, 形成一个正向的循环.

然而这却恰恰是最难的, 尤其是对前端来说, 很多时候我们在工作中很少或者几乎不会真正的去考虑数据结构和算法, 我们所知的 JavaScript 中的 对象 和 数组很难和书本上的数据结构映射起来, 自然更不用提那些简单的或者复杂的算法了, 那对于前端, 数据结构和算法难道真的只是用来敲开一些大厂的敲门砖, 只是一种面试工具么?

正文

前端群体这些年埋下的隐患

在我从事前端开发的这些年, 我有一种很强烈的感受, 就是虽然我们一直再提程序设计, 再学习设计模式, 而且每年都会有人把这些模式挖出来分享分享, 但我从来没感受到 设计 两个字在我们的工作中有任何体现. 我们编写代码, 开发应用, 也很少强调设计, 大多数项目没有任何设计文档, 多人协作开发也从来不需要做设计上的讨论, 可能有一些设计评审, 但大多数时候都是形式大于内容

起初我觉得可能是因为互联网项目不像传统软件项目那样具有长生命周期, 大多数过于短命, 加上长期以来创业者被投资机构灌输的

"快, 更快, 你只有比别人跑得快, 你才能活下来"

在这种短跑快餐式的创业文化驱动下, 大多数公司都强调快速上线, 作为研发人员, 自然也经常被教育

"别想太多, 先写, 先拿结果再说, 月底必须上线"

在这环境下导致前端程序设计缺失, 程序员被逼着边写边想, 边想边改, 边改边删. 但是最近我突然领悟或许这并不是前端程序设计缺失的根本原因, 其根本原因在于前端程序设计的门槛太低了, 并且 JavaScript 提供了 对象 这个超级灵活简单的数据结构, 而且 对象 内部的算法都经过了封装, 前端程序在非常多的场景下都只需要使用提供好的 api 并不需要自己实现相应的算法, 加上浏览器提供的开发环境修改程序的成本低到忽略不计, 这就好比

当一件事的修改成本无限低的时候, 我们会倾向于先做, 做错了改就是了, 而当一件事的修改成本很高, 一旦出错就要付出非常大的代价, 我们会倾向于先想清楚再做, 避免修改带来的巨大痛苦, 但如果这件事的修改成本是非线性增长, 越往后越成本越高的时候, 我们往往会陷入温水煮青蛙般的困境, 而前端恰恰就是如此

过去短命的互联网创业项目掩盖了这种弊端, 作为前端程序员你不需要刻意的提升自己的程序设计能力, 通过反复开发相同程度的程序就能获得较高的薪水回报, 但随着互联网行业越来越成熟, 越来越多的项目进入了成熟期, 早期不强调设计带来的恶果正在不断显现, 大量的 Bug 和维护上的困难导致的重构工作让本就丧失程序设计能力的前端程序员苦不堪言. 没有设计的重构只是把一坨屎压成一滩屎, 以便看起来没有这么恶心, 但随着时间推移, 重构变成了重做, 重做做成了烂尾项目.

低门槛, 高效开发让前端程序员尝到了互联网的资本红利, 但大量的短期的重复性的项目也扼杀了这个群体的核心能力, 以至于大多数前端程序员都不具备合格的程序设计能力, 从来也没有真正理解或者掌握过数据结构和算法

重新理解 "程序 = 数据结构 + 算法"

如果我问一个问题, 对于程序员来说最重要的能力是什么? 可能会有人回答

"算法掌握的好"

"逻辑思维"

"抽象能力"

"技术之外的业务理解能力", "..."

但我想说, 这些都很重要, 但就如程序员的名字一般, 我们是写程序的, 程序员的最核心能力就如 程序 = 数据结构 + 算法 这个公式所描述的那样, 将程序分解成数据结构和算法的能力, 又因为程序本身是现实世界的数字化, 因此更准确的说法应该是 将对现实世界的理解分解成数据结构和算法的能力

因此当我们谈程序设计, 强调设计能力的时候其实就是在强调如何使用改造甚至发明数据结构以及相匹配的算法的过程.

以我们熟知的 TODOMVC 为例, GitHub 该项目主要是用来对比不同的 mvc 框架在实现 TODO 上的优劣. 但如果从程序设计角度来看, 我们不应该关心用什么框架是实现 TODOMVC, 无论是 Redux 还是老旧的 Backbone 还是 ReactHook 又或者是 Vuex? 程序设计要求我们在更高的抽象层面进行设计工作, 具体选用哪种实现可能是最后一步了. 对于 TODO 这样一个应用来说, 第一步应该先考虑在现实世界里 TODO 是怎样的一个应用, 这部分工作通常由产品经理和设计师完成.

程序的一面是现实世界

当我们最终做出一个应用, 在用户的手机上运行, 用户所看到的所感知到的都是这个程序在现实世界里的一面, 产品经理将现实世界里人的需求整理出来并基于某些特定的操作设备或者操作环境构思原型, 并交由设计师进行润色和具象化, 直到交付到程序员手中, 我认为这部分也是程序的一部分, 是程序的现实面

程序的另一面是数字世界

当程序员看到程序的现实面, 我们的工作便是要设计和实现程序的另一面 - 数字面. 在这个过程中, 我们需要拆解现实面, 将现实面中的静态部分抽象成各种数据结构, 并且确保这些数据结构之间具备合理的联系, 并预留一些设计为静态是现实面的扩展留出空间

现实面的静态部分, 即我们眼睛所看到的, 在 TODO 这个应用中包括视觉效果, 界面, 属性.

并将现实面的动态部分抽象成算法, 并且确保这些算法的执行效率不会超出现实面中运行设备的平均值

程序的现实面即原型, 都是假定在某些特定设备中运行的, 作为程序设计者你需要充分考虑你的程序中的算法在这些设备上的执行效率 现实面的动态部分指的是那些会导致变化的动作, 在 TODO 这个应用中包括 UI 上的操作, 例如 勾选, 滑动, 下拉等等, 或者是对数据的操作, 例如完成某个代办, 删除某个待办等等.

然而对于大多数非科班的前端程序员, 或者不注重程序设计的前端程序员来讲, 我们拿到 TODO 这样的一个应用的原型, 极大概率就是

啥也别说, 先把 CSS 写起来, JavaScript 写起来, 好不好用, 浏览器试下就知道了

回到标题, 作为前端该如何学好数据结构与算法?

答案是不言而喻的, 作为前端程序员要真正掌握数据结构和算法, 必须先从每一个微小的程序设计开始, 摆脱边写边想的开发方式, 认真理解和思考程序的现实面, 并通过你所了解的数据结构和算法, 将现实面抽象出来变成数字面, 而只有在这样一次一次的设计中不断积累经验, 不断深入掌握和理解并学习各种数据结构和算法, 你才能真正理解程序的本质, 看透那些成功的开源项目背后的设计, 而不仅仅是停留在看源码, 梳理逻辑, 看过就忘的这种境界. 比如 React 16 的程序设计主要是基于 单链表 两种数据结构以及相关的算法, Webpack 的程序设计是围绕 以及相关算法, 进一步往上抽象 React 的 Fiber 模型, 基于 Fiber 的调度算法, Webpack 构建的事件管道, 这些设计模型本身也是建立在基础的数据结构之上的, 没有对数据结构和算法的理解就无法设计出这样的模型, 同理, 四人帮的设计模式也都是建立在各种数据结构和算法之上

所以对数据结构和算法的掌握, 不是看你是否拥有各种熟练的解题技巧, 而是能否使用基本的数据结构和算法, 通过优化与改造来抽象程序的现实面, 设计出具有良好扩展性与优良性能的程序

因此让我们回归设计的原点, 重新看看那些基础的数据结构和算法, 在看看你至今写过的那么多代码里, 有多少你用上了, 但是却总来没感觉自己用过, 有多少你曾经写过的程序其实可以更好的设计和抽象?

后话

从 13年 10月开始从事前端方面的工作, 差不多快 7个年头, 但直到最近我才发现不是前端不需要数据结构和算法, 而是对于一个新的技术领域我们缺乏足够的思考和探索, 其实数据结构和算法从未离开过前端, 也一直在前端这个领域中隐藏着, 我们编写的每一行代码无意中都包含着, 但却从来没有真正被我们所理解, 也从来没有认真的思考过前端程序设计这个问题. 我相信跟我一样顶着 前端工程师 这样名号的这一代前端程序员或多或少都有些名不副实, 我们做着工程设计, 做着架构设计, 却连最基本的数据结构和算法都未曾真正掌握, 这样设计出来的架构设计出来的系统真的可靠么? 真的经得起时间的考验么? 为此我试着以一个初学者的心态重新来看待前端程序设计这个问题, 也希望有相同感受的 前端工程师 能参与这样的探索, 是时候让我们为后来的前端程序员留下些有价值的东西了.