内容大纲
一、这篇想传达的
二、开场问题
三、软体开发的学习难题
四、该怎么解决?理解并梳理思考脉络
五、理解思考脉络的本质,注意学习的陷阱
六、结论
HackMD 好读连结
HackMD 系列目录
一、这篇想传达的
第一篇针对了「被动学习」和「主动学习」,传达了看不到终点的学习焦虑和烦恼,主要来自于自己的学习认知和状态。
接下来希望透过这篇,传达学习程式技术的方向问题,为何主要源自于思考脉络的杂乱,导致学了东,忘了西,学了一堆,等到需要拼在一起综合运用的时候,脑袋一片空白。
除此之外,第二篇内容会延伸第一篇提到的内容:如何混用专案式学习和实验式学习。
二、开场问题
以下几位正面临学习烦恼的人,描述了他们的学习方式和烦恼,先将他们的描述放进脑海当中,看完本文之后,思考看看,除了建议对方直接躺平,你会怎么点出对方的问题?
A君:工作需要接触 Angular 框架
我是某公司的 Junior 前端工程师,接下来需要接手几个 Angular 的专案,在前两个月,我很努力的把官方文件的内容都一个一个看完并且跟着做,第三个月开始,我準备接手一个 Angular 专案,里面的程式码都看过,但是每次需要调整某个页面的功能、新增某个页面的时候,却不知道从何下手,我是不是要回去複习 Angular 的官方文件?
B君:从 .NET 6 框架转换到 Spring Boot 2.7 框架
我是公司的后端工程师,在公司已经待了一年,由于公司的专案,主要使用的后端框架除了 C#.NET 6,还有 Java Spring Boot 2.7,因此主管希望我去接触和学习,但我没有 Java 的基础,而且 Spring 又有 Spring Boot、Spring WebFlux、Spring Data、Spring Security 这么多要学,我到底该从何学习?
C君:準备踏入前端工程师
我每天花了很多时间观看网路上的 HTML & CSS 教学,把所有的 HTML 标籤和 CSS 语法记下来,但我总是容易搞混不同的标籤和语法,<head> 跟 <body> 差在哪、<link> 跟 <script> 差别在哪?CSS 的 vertical-align 和 justify-content 差别在哪?
D君:工作需要接触 Linux
我是某个初阶后端工程师,因为许多的专案都是架设在 Linux 环境,因为听大家说鸟哥的书超级讚,结果买来之后看了一个月,发现要记的指令和常用资料夹路径超多,越是学到后面,前面学过的指令和观念越是没有印象,我需要从头回去複习前面的内容吗?
三、软体开发的学习难题
从上述四位的描述当中,你能否想像他们所学的东西,在脑中是什么样子?思考路径不仅混乱,而且观念抽象没有连结。
为什么?多数有方向和混乱的问题,因为在学习时,聚焦在学习的内容,忽略或甚至轻忽学习的思考脉络。
假设一个学了变数、条件判断、输入和输出语法,但没有方向完成 Console 版猜数字游戏(1~100 猜一个整数)的人做类比,他们脑中的思考脉络大概长这个样子:
这样的思考脉络究竟有哪些问题?
(一) 每个脉络之间的路径没有主次和顺序之分 (迷路)
大脑的思考路径,不知道主要先想哪些,其次想哪些。
最直接的结果:不知道从何下手,脑袋一片空白。
对应到第一张思考脉络图:
每条思考路径的粗细、颜色、深浅都一样,随着学的东西越来越多,思考路径也容易越来越跳跃。
(二) 每个脉络之间的路径是分散且无法连结的 (混乱易忘)
程式开发这个领域,许多的观念、语法,对大脑来说都是相当的「抽象」而且「没感觉」。如果反覆死记硬背,记到后来不只难以回想,又容易遗忘。
对应到第一张思考脉络图:
每条思考路径之间分散且没有连贯,随着学的东西越来越多,思考路径也容易变得越来越难发现。
四、该怎么解决?理解并梳理思考脉络
(一) 以刚才的猜数字游戏为例,学习时该怎么整理思考脉络?
如果要使用 C# 完成一个 Console 的猜数字游戏,第一层要想的事情有哪些?- **首先,怎么从 1~ 100 的整数,产生并记录正确答案**- **接着,玩家怎么输入答案,并记录在程式**- **再来,如何比对玩家的答案与正确答案一样**- **最后,怎么输出比对的结果,告知玩家答对还是答错**
当我把第一层的思考脉络整理之后,最后会是下图的样子。第一层思考路径,就像这颗树一样,一开始从中间的树干,从下到上,依序往两侧的树枝思考。
一旦主次和顺序整理出来之后,每次回想猜数字游戏的时候,都能很快的从这四个问题切入。
回到刚刚猜数字游戏的例子,第一层脉络整理出了,猜数字游戏要依序解决的问题情境。接着依序思考,每个问题情境需要用到哪些程式观念和语法?- **首先,怎么从 1~ 100 产生并记录正确答案** - 乱数:使用 Random 产生乱数 - int 型态:产生完的整数乱数,使用整数(int)型态的变数存放- **接着,玩家怎么输入答案,并记录在程式** - 输入的函数 Console.ReadLine() - 输入的资料使用字串型态的变数存放 (string)- **再来,如何比对玩家的答案与正确答案一样** - 条件判断: if {} else {}、三元运算子 - 比较运算: if (userAnswer == inputAnswer) - 型态转换:字串跟整数比较前需要将字串转成整数型态 int.Parse() 或 Convert.ToInt32()- **最后,怎么输出比对的结果,告知玩家答对还是答错** - 输出函数:使用 Console.WriteLine()
当我把第二层的思考脉络整理之后,最后会是下图的样子。
学完整理出完整的脉络后,原本抽象而且没感觉的语法,和第一层的问题情境有了连结,有助于语法观念的记忆和联想。
接着就可以依照自己的需要,深入学习和实验每个语法观念。例如:我想要了解更多乱树的用法,可以新增一只实验用的程式专案,去了解和实验每个乱数的函数。因为有了脉络之后再看语法观念,跟你一开始直接看语法观念的感觉会完全不一样。
备注:因为这篇要把思考脉络的「路径」强调出来,所以使用树来做比喻,你也可以使用心智图来整理。
(二) 从 C# 转换为 JavaScript
继续延伸猜数字游戏的例子:
如果今天改从 C# 换到在浏览器的 Console,使用弱型别的 JavaScript 实现,你会发现哪些差别?第二层的程式语法和观念细节。1. **乱数产生的函数**:Math.random()。 【语法差异】2. **int 型态**:使用 let 宣告,而且不需要型态。 【语法差异+语言特性】3. **输入函数**:如果是浏览器的 prompt() 当作输入函数。 【语法差异】4. **型态转换**:parseInt()。 【语法差异】5. **比较运算**:除了严格相等 (===),即使型态不同,弱型别的语言也会自动转换。 【语言特性】 6. **输出函数**:console.log()
(三) 从 Console 转换为网页
在转换相似的思考脉络当中,你也整理了当中的语法差异和语言特性差异。同样的还可以练习看看:
如果要从 Console 改成网页表单的形式,原本的脉络会怎么变化?这边以**第一层脉络**的「输入答案」和「比对答案」,使用原生 JavaScript 为例:- ~~输入函数~~ **表单**:栏位的说明 (label) 、输入的栏位 (input)送出按钮(Button))- **事件(event)**:表单送出事件(submit) 或按钮事件 (click)- **取得 input 的内容**:submit 事件的 event.target\['xxx'].value 或使用 document.querySelector('yyy').value 从 DOM 下手
当你学习时,从整理的脉络发现,对于表单、DOM、事件的观念不太熟悉时,你就可以抽一些时间,深入学习这几个部分的整体观念。
(四) 从 Console 版猜数字游戏加入功能变化
除了用来转换到不同的语言或工具,还可以加入变化,如果觉得抽象,可以自己尝试照着上面的原则,「主要先想那些,哪些是次要接着想的,观念和问题该怎么连结。」将思考脉络条列并画出来:
在 Console 的猜数字游戏,加上「可以重複猜测直到答对」、「最多猜测十次」、「最大最小的範围提示」、「再玩一轮」等功能。- **可以重複猜测直到答对**:在第一层脉络上,多了一条分支「可以重複猜测直到答对」,往下延伸一条第二层分支: while 迴圈,重複的条件为「使用者答案 不等于 正确答案」 (userAnswer != correctAnswer)。- **最多猜测十次**: - 第一层「计算并判断作答次数」,底下延伸一条「算术运算」。 - 接着回到第一层,想到刚才的「可以重複猜测直到答对」,重複的条件改为「『使用者答案 不等于 正确答案』,而且『猜测的次数 小于等于 5 (初始值从1开始)』」(userAnswer != correctAnswer && guessTime <= 5)。- **最大最小的範围提示**:第一层先想到「比对答案」,接着想到「条件判断」,原本的程式逻辑只有「答对(\==)」、「答错(!=)」,加上提示範围的程式逻辑变成「答对(\==)」、「比答案小(<=)」、「比答案大(>=)」。- **再玩一轮**:第一层脉络,多了一条分支「再玩一轮」,底下延伸两条第二层分支,包含 「do...while 迴圈」和「输入函数」。
(五) 总结整理脉络的重点
对应第一篇提到的专案式学习和实验式学习,在专案式练习,关注三个部分:
釐清与拆解涵盖的问题情境:思考路径的切入点整理问题情境的主次层级:思考的层级顺序将相对具体的问题情境,连结到陌生且抽象的观念:思考的连贯性。当你透过实验式学习,深入了解某一个路径的观念时,用相同的原则,将某个路径从原先的脉络拉出来思考,整理成另一个抽象语法或观念的思考脉络。
(六) 总结思考脉络的好处
往后在回想的时候,不管你从问题情境的角度切入往下延伸,或者从抽象语法观念的角度切入往前回想,思考脉络对你来说整体又容易掌握。
容易找到思考的切入点描述问题的时候,其他人比较容易理解并找到问题的癥结点。有助于记忆和回想抽象的语法观念
快速的从第一层问题脉络的连结当中,找到和理解每个抽象的观念和细节。转换学习时,帮助掌握共通点与差异点
换到不同的语言、工具或技术时,可以当作转换的方向,专注在脉络当中的差异点、较弱的观念。
(七) 整理思考脉络的盲点
语法或观念细节要怎么办?
整理思考脉络的重点在,整理思考的路径,所以流程或语法观念的细节,比较建议整理成文章、程式档的形式。不在第二篇的讨论範围。
最多延伸到几层?每一个层级要固定放什么?
没有标準答案,只要思考时,路径能自然的连贯起来。
(八) 没经验或缺乏基础的人,整理思考脉络会遇到的状况
想不到一开始的切入点
从问题情境或实现的功能切入并拆解。
如果认为发现实在有难度,我会直接建议找专案导向的书或课程 + Google 学习。
钻牛角尖,或者过于发散。
通常是想的「太细」,或者「不够具体直接」,可以试着拉高层级,整理归纳较为细节的脉络。
某个思考路径,超出自身的认知,卡住无法往下延伸。
思考跟目前的学习重点有关,如果连结性较小,选择性的暂时搁置。
以上三点拿开场问题的B君学习 Spring Boot 为例,没整理过的思考脉络可能长这个样子:1. Java 的 JDK 与 JRE2. IDE 或编辑器3. Maven 或 Gradle 的使用4. 怎么启动 Spring Boot 的 API 测试5. 怎么定义 GET, POST, PUT, PATCH, DELETE 的 API6. API 的请求参数和回应参数怎么定义和存取。7. 连线资料库的设定。8. 资料表与栏位的 Class 定义。9. SQL 操作在 Hibernate 的架构下该怎么实作。10. 实作基本的会员相关功能...经过整理后的思考脉络:1. 开发前的準备:开发环境、开发工具 - Java 的 JDK 与 JRE - 开发用的 IDE 或编辑器2. 怎么建立和启动一个专案 - 怎么使用 Maven 或 Gradle 安装套件 - 使用什么指令启动 API 测试。3. 以前写过的会员系统,在 Spring Boot 是怎么实作的 - 如何定义 WebAPI - 怎么定义 GET, POST, PUT, PATCH, DELETE 的 API - API 的请求参数和回应参数怎么定义和存取。 - 相依服务的设定和使用 - 定义为可被注入的相依服务类别 (建立 Bean) - 注入其他的相依服务类别 (注入 Bean) - 搭配关连式资料库 - 连线资料库的前置设定。 - 资料表与栏位的 Class 定义。 (Model) - SQL 基本 CRUD 操作在 Hibernate 的架构下该怎么实作。 (Repository) - 怎么实作关联查询 (Join) - 怎么使用资料库的交易 (Transaction) - 注册的商业逻辑 - 判断帐号是否重複注册 - 判断密码的强度 - 判断密码与确认密码是否一样 - 密码的加盐 - 登入的商业逻辑 ... - 登出的商业逻辑 ... - 忘记密码的商业逻辑 ...
如果你不像 B 君有足够的经验,延伸几点学习上的建议:
记录下来当前常常卡住的部分,抽时间一起学习
如果在学习 Spring Boot 的时候,发现 SQL、@Autowird 和 @Component 等等观念和用法,常常让你觉得卡东卡西,我会记录下来,花点时间把卡住的观念和语法整个学过一遍,另外开个实验专案尝试并观察。
準备一至两个自己能从头到尾完成,而且相对完整的作品,找个练功的第一份工作
练习的过程中,或许你的作法并不是 Best Practice,Code 写的不是很好,或者有些脉络是自学不容易接触到的,但至少你有了属于自己的学习脉络和纪录。
先挑一个要求没这么高的低阶工作练功,进入职场之后,跟随较资深的前辈做中学,将有毒的作法、设计调整过来,并且补足自学不容易掌握的思考脉络。很多对程式码好坏很敏锐的人,也是接手过别人的烂 Code,或者自己的烂 Code。如果是一位天份不错的人,自认作品的 Level 比其他人高,那第一份工作就可以挑比较好的去挑战,因人而异。
五、理解思考脉络的本质,注意学习的陷阱
(一) 思考脉络是给「自己」的大脑用的
看完了思考脉络的说明和举例,我需要特别强调,思考脉络是给自己用的。换句话说:
主要必须靠自己思考和整理,别人的不一定适用自己。可随时不断的调整。每个人不会完全相同。只有靠自己思考和整理的思考脉络,印象才会最深刻,思考起来才会灵活。
(二) 「速成笔记」或「技巧」的使用时机避免过早
因此我会建议在刚开始学习程式的时候,最好避免:
密技思维:刚开始学习,就直接使用网路或别人整理好的心智图、学习路径 (Road Map)、Cheat Sheet、XXX 个技巧学习。思考重心流于整理笔记,偏离思考事情本身。抄捷径的密技和方法,适合在有一定思考脉络的时候,补足不足的部分,但如果当作一开始主要学习的内容,反而是大脑整理思考脉络的杀手。为什么?
工作面临的开发与除错问题,很多都是综合性的问题,没有脉络的密技和技巧,很容易会以东拼西凑的角度切入,遇到问题越补越大洞、方向越来越偏。
(三) 当作一种习惯养成,而非唯一的万用工具
要练习多久?有什么方法技巧快速练成?有哪些练习的题材?当作一种习惯养成,用在整理平常学习的专业、工作的每一件事情,之间的主次与关联,时间因人而异。是不是只要会整理思考脉络,就能快速具备工程师的能力?
当然不是,整理完思考脉络,只是帮你整理掌握整体的结构和方向,你还是要下功夫去理解、练习学习的内容。
六、结论
专案式学习面对的问题情境、完成的功能,在学习的时候帮助蒐集、釐清、整理思考脉络,混用实验式学习,可以在有整体脉络的支撑下,专心强化所学的理论。
看文本篇内容之后,我们来整理一下文章的思考脉络:
除了学习,工作要接手陌生的专案、文章或会议纪录的大纲、找程式问题,有没有习惯整理思考脉络,做事的效率也会有明显的差别。
最后以开场问题的 A 君来进行总结:
A 君可以从网站的角度切入第一层脉络,Angular 前端框架主要处理的问题有哪一些(以下是简单举例):- 开发的前置作业:开发环境的设定- 管理网站底下的所有页面位置:网站的路由- 元件开发 - 页面 UI 元件 - 共用 UI 元件- API 串接的服务层- 整个网站的资料共用: - 服务 (Service) - 状态管理 (NgRx)- 多语系- 环境变数- 建置与部署
随着时间,不断累积开发处理的问题和情境,加上框架本身的更新变化,A君对于 Angular 的思考脉络也会跟着改变。不同的人,对于 Angular 的思考脉络也不会一样。
C、D君,两位的思考脉络,就留给读者自己整理看看。
题外话:曾经下班为了练习 Angular 13,透过完成 UI Libary 的过程,熟悉 Angular 13 大部分的 UI 元件的语法,有兴趣可以参考看看,怎么转成新版的 Standalone & Control Flow 写法:https://ngx-youi.github.io/NGX-YOUI/
第二篇内容到这边结束,谢谢大家耐心的阅读。