-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
index.html
4039 lines (3991 loc) · 366 KB
/
index.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="generator" content="pandoc">
<meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes">
<title>Growth: 全栈增长工程师指南 – </title>
<style type="text/css">code{white-space: pre;}</style>
<style type="text/css">
div.sourceCode { overflow-x: auto; }
table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
margin: 0; padding: 0; vertical-align: baseline; border: none; }
table.sourceCode { width: 100%; line-height: 100%; }
td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
td.sourceCode { padding-left: 5px; }
code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
code > span.dt { color: #902000; } /* DataType */
code > span.dv { color: #40a070; } /* DecVal */
code > span.bn { color: #40a070; } /* BaseN */
code > span.fl { color: #40a070; } /* Float */
code > span.ch { color: #4070a0; } /* Char */
code > span.st { color: #4070a0; } /* String */
code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
code > span.ot { color: #007020; } /* Other */
code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
code > span.fu { color: #06287e; } /* Function */
code > span.er { color: #ff0000; font-weight: bold; } /* Error */
code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
code > span.cn { color: #880000; } /* Constant */
code > span.sc { color: #4070a0; } /* SpecialChar */
code > span.vs { color: #4070a0; } /* VerbatimString */
code > span.ss { color: #bb6688; } /* SpecialString */
code > span.im { } /* Import */
code > span.va { color: #19177c; } /* Variable */
code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
code > span.op { color: #666666; } /* Operator */
code > span.bu { } /* BuiltIn */
code > span.ex { } /* Extension */
code > span.pp { color: #bc7a00; } /* Preprocessor */
code > span.at { color: #7d9029; } /* Attribute */
code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
</style>
<link rel="stylesheet" href="style.css">
<!--[if lt IE 9]>
<script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
<![endif]-->
<meta name="viewport" content="width=device-width">
</head>
<body>
<h1>Growth: 全栈增长工程师指南</h1>
<p>By <a href="https://www.phodal.com/">Phodal</a> (Follow Me: <a href="http://weibo.com/phodal">微博</a>、<a href="https://www.zhihu.com/people/phodal">知乎</a>、<a href="https://segmentfault.com/u/phodal">SegmentFault</a>)
</p>
<p>GitHub: <a href="https://github.com/phodal/growth-ebook">Growth: 全栈增长工程师指南</a></p>
<p>
<strong>下载</strong>:
<a href="https://github.com/phodal/growth-ebook/releases/download/0.9.9/growth.epub">Epub版</a>、<a href="https://github.com/phodal/growth-ebook/releases/download/0.9.9/growth.mobi">Mobi版</a>、<a href="https://github.com/phodal/growth-ebook/releases/download/0.9.9/growth.pdf">PDF版</a>、<a href="https://github.com/phodal/growth-ebook/releases/download/0.9.9/growth.rtf">RTF版</a>
<p>
<h3>购买纸质版 Growth:《全栈应用开发:精益实践》</h3>
<p><img src="./marketing/growth-paper.jpeg" alt=""/></p>
<p>京东:<a href="http://item.jd.com/12195442.html">http://item.jd.com/12195442.html</a></p>
<p>当当: <a href="http://product.dangdang.com/25077858.html">http://product.dangdang.com/25077858.html</a></p>
<p>
亚马逊: <a href="https://www.amazon.cn/dp/B0722YJR89">https://www.amazon.cn/dp/B0722YJR89</a>
</p>
<h3>
Warning: 请与
<a href="https://github.com/phodal/growth-in-action-django">《Growth:全栈增长工程师实战》</a> 一起阅读
</h3>
<p>
阅读过程中遇到语法错误、拼写错误、技术错误等等,不妨来个Pull Request,这样可以帮助到其他阅读这本电子书的童鞋。
</p>
<p>我的其他电子书:</p>
<ul>
<li>《<a href="https://github.com/phodal/designiot">一步步搭建物联网系统</a>》</li>
<li>《<a href="https://github.com/phodal/github-roam">GitHub 漫游指南</a>》</li>
<li>《<a href="https://github.com/phodal/repractise">RePractise</a>》</li>
<li>《<a href="https://github.com/phodal/ideabook">一个全栈增长工程师的练手项目集</a>》</li>
</ul>
<p>
<p>微信公众号</p>
<p><img src="./marketing/wp.jpg" alt=""/></p>
<p>
<div style="width:800px">
<iframe src="http://ghbtns.com/github-btn.html?user=phodal&repo=growth-ebook&type=watch&count=true"
allowtransparency="true" frameborder="0" scrolling="0" width="110px" height="20px"></iframe>
</div>
<nav id="TOC">
<ul>
<li><a href="#growth-全栈增长工程师指南">Growth: 全栈增长工程师指南</a><ul>
<li><a href="#关于作者">关于作者</a></li>
<li><a href="#全栈工程师是未来">全栈工程师是未来</a><ul>
<li><a href="#技术的革新史">技术的革新史</a></li>
<li><a href="#软件开发的核心难题沟通">软件开发的核心难题:沟通</a></li>
<li><a href="#大公司的专家与小公司的全栈">大公司的专家与小公司的全栈</a></li>
<li><a href="#全栈工程师的未来无栈">全栈工程师的未来:无栈</a></li>
</ul></li>
</ul></li>
<li><a href="#基础知识篇">基础知识篇</a><ul>
<li><a href="#工具只是辅助">工具只是辅助</a><ul>
<li><a href="#webstorm-还是-sublime">WebStorm 还是 Sublime?</a></li>
<li><a href="#语言也是一种工具">语言也是一种工具</a></li>
</ul></li>
<li><a href="#提高效率的工具">提高效率的工具</a><ul>
<li><a href="#快速启动软件">快速启动软件</a></li>
<li><a href="#ide">IDE</a></li>
<li><a href="#debug-工具">DEBUG 工具</a></li>
<li><a href="#终端或命令提示符">终端或命令提示符</a></li>
<li><a href="#包管理">包管理</a></li>
</ul></li>
<li><a href="#环境搭建">环境搭建</a><ul>
<li><a href="#os-x">OS X</a></li>
<li><a href="#windows">Windows</a></li>
<li><a href="#gnulinux">GNU/Linux</a></li>
</ul></li>
<li><a href="#学好一门语言的艺术">学好一门语言的艺术</a><ul>
<li><a href="#一次语言学习体验">一次语言学习体验</a></li>
<li><a href="#输出是最好的输入">输出是最好的输入</a></li>
<li><a href="#如何应用一门新的技术">如何应用一门新的技术</a></li>
</ul></li>
<li><a href="#web-编程基础">Web 编程基础</a><ul>
<li><a href="#从浏览器到服务器">从浏览器到服务器</a></li>
<li><a href="#从-html-到页面显示">从 HTML 到页面显示</a></li>
</ul></li>
<li><a href="#html">HTML</a><ul>
<li><a href="#helloworld">hello,world</a></li>
<li><a href="#中文">中文?</a></li>
<li><a href="#其它-html-标记">其它 HTML 标记</a></li>
<li><a href="#小结-1">小结</a></li>
</ul></li>
<li><a href="#css">CSS</a><ul>
<li><a href="#简介">简介</a></li>
<li><a href="#样式与目标">样式与目标</a></li>
<li><a href="#选择器">选择器</a></li>
<li><a href="#更有趣的-css">更有趣的 CSS</a></li>
</ul></li>
<li><a href="#javascript">JavaScript</a><ul>
<li><a href="#helloworld-1">hello,world</a></li>
<li><a href="#javascriptful">JavaScriptFul</a></li>
<li><a href="#面向对象">面向对象</a></li>
<li><a href="#其他">其他</a></li>
</ul></li>
</ul></li>
<li><a href="#前端与后台">前端与后台</a><ul>
<li><a href="#后台语言选择">后台语言选择</a><ul>
<li><a href="#javascript-1">JavaScript</a></li>
<li><a href="#python">Python</a></li>
<li><a href="#java">Java</a></li>
<li><a href="#php">PHP</a></li>
<li><a href="#其他-1">其他</a></li>
</ul></li>
<li><a href="#mvc">MVC</a><ul>
<li><a href="#model">Model</a></li>
<li><a href="#view">View</a></li>
<li><a href="#controller">Controller</a></li>
<li><a href="#更多-1">更多</a></li>
</ul></li>
<li><a href="#后台即服务">后台即服务</a><ul>
<li><a href="#api-演进史">API 演进史</a></li>
<li><a href="#后台即服务-1">后台即服务</a></li>
</ul></li>
<li><a href="#数据持久化">数据持久化</a><ul>
<li><a href="#文件存储">文件存储</a></li>
<li><a href="#数据库">数据库</a></li>
<li><a href="#搜索引擎">搜索引擎</a></li>
</ul></li>
<li><a href="#前端框架选择">前端框架选择</a><ul>
<li><a href="#angular">Angular</a></li>
<li><a href="#react">React</a></li>
<li><a href="#vue">Vue</a></li>
<li><a href="#jquery-系">jQuery 系</a></li>
</ul></li>
<li><a href="#前台与后台交互">前台与后台交互</a><ul>
<li><a href="#ajax">Ajax</a></li>
<li><a href="#json">JSON</a></li>
<li><a href="#websocket">WebSocket</a></li>
</ul></li>
</ul></li>
<li><a href="#编码">编码</a><ul>
<li><a href="#编码过程">编码过程</a></li>
<li><a href="#web-应用的构建系统">Web 应用的构建系统</a><ul>
<li><a href="#web-应用的构建过程">Web 应用的构建过程</a></li>
<li><a href="#web-应用的构建实战">Web 应用的构建实战</a></li>
</ul></li>
<li><a href="#git-与版本控制">Git 与版本控制</a><ul>
<li><a href="#版本控制">版本控制</a></li>
<li><a href="#git">Git</a></li>
</ul></li>
<li><a href="#tasking">Tasking</a><ul>
<li><a href="#如何-tasking-一本书">如何 Tasking 一本书</a></li>
<li><a href="#tasking-开发任务">Tasking 开发任务</a></li>
</ul></li>
<li><a href="#写代码只是在码字">写代码只是在码字</a></li>
<li><a href="#内置索引与外置引擎">内置索引与外置引擎</a><ul>
<li><a href="#门户网站">门户网站</a></li>
<li><a href="#内置索引与外置引擎-1">内置索引与外置引擎</a></li>
</ul></li>
<li><a href="#如何编写测试">如何编写测试</a><ul>
<li><a href="#测试金字塔">测试金字塔</a></li>
<li><a href="#如何测试">如何测试</a></li>
</ul></li>
<li><a href="#测试替身">测试替身</a><ul>
<li><a href="#stub">Stub</a></li>
<li><a href="#mock">Mock</a></li>
</ul></li>
<li><a href="#测试驱动开发">测试驱动开发</a><ul>
<li><a href="#红-绿-重构">红-绿-重构</a></li>
<li><a href="#测试先行">测试先行</a></li>
</ul></li>
<li><a href="#可读的代码">可读的代码</a><ul>
<li><a href="#命名">命名</a></li>
<li><a href="#函数长度">函数长度</a></li>
<li><a href="#其他-2">其他</a></li>
</ul></li>
<li><a href="#代码重构">代码重构</a><ul>
<li><a href="#重命名">重命名</a></li>
<li><a href="#提取变量">提取变量</a></li>
<li><a href="#提炼函数">提炼函数</a></li>
</ul></li>
<li><a href="#intellij-idea-重构">Intellij Idea 重构</a><ul>
<li><a href="#提炼函数-1">提炼函数</a></li>
<li><a href="#内联函数">内联函数</a></li>
<li><a href="#查询取代临时变量">查询取代临时变量</a></li>
</ul></li>
<li><a href="#重构到设计模式">重构到设计模式</a><ul>
<li><a href="#过度设计与设计模式">过度设计与设计模式</a></li>
</ul></li>
</ul></li>
<li><a href="#上线">上线</a><ul>
<li><a href="#隔离与运行环境">隔离与运行环境</a><ul>
<li><a href="#隔离硬件虚拟机">隔离硬件:虚拟机</a></li>
<li><a href="#隔离操作系统容器虚拟化">隔离操作系统:容器虚拟化</a></li>
<li><a href="#隔离底层servlet-容器">隔离底层:Servlet 容器</a></li>
<li><a href="#隔离依赖版本虚拟环境">隔离依赖版本:虚拟环境</a></li>
<li><a href="#隔离运行环境语言虚拟机">隔离运行环境:语言虚拟机</a></li>
<li><a href="#隔离语言dsl">隔离语言:DSL</a></li>
</ul></li>
<li><a href="#lnmp-架构">LNMP 架构</a><ul>
<li><a href="#gnulinux-1">GNU/Linux</a></li>
<li><a href="#http-服务器">HTTP 服务器</a></li>
</ul></li>
<li><a href="#web-缓存">Web 缓存</a><ul>
<li><a href="#数据库端缓存">数据库端缓存</a></li>
<li><a href="#应用层缓存">应用层缓存</a></li>
<li><a href="#前端缓存">前端缓存</a></li>
<li><a href="#客户端缓存">客户端缓存</a></li>
<li><a href="#html5-离线缓存">HTML5 离线缓存</a></li>
</ul></li>
<li><a href="#可配置">可配置</a><ul>
<li><a href="#环境配置">环境配置</a></li>
<li><a href="#运行机制">运行机制</a></li>
<li><a href="#功能开关">功能开关</a></li>
</ul></li>
<li><a href="#自动化部署">自动化部署</a><ul>
<li><a href="#依赖与包仓库">依赖与包仓库</a></li>
<li><a href="#构建软件包">构建软件包</a></li>
<li><a href="#上传和安装软件包">上传和安装软件包</a></li>
</ul></li>
</ul></li>
<li><a href="#数据分析">数据分析</a><ul>
<li><a href="#构建-衡量-学习">构建-衡量-学习</a><ul>
<li><a href="#想法-构建">想法-构建</a></li>
<li><a href="#产品-衡量">产品-衡量</a></li>
<li><a href="#数据-学习">数据-学习</a></li>
</ul></li>
<li><a href="#数据分析-1">数据分析</a><ul>
<li><a href="#识别需求">识别需求</a></li>
<li><a href="#收集数据">收集数据</a></li>
<li><a href="#分析数据">分析数据</a></li>
<li><a href="#展示数据">展示数据</a></li>
</ul></li>
<li><a href="#用户数据分析google-analytics">用户数据分析:Google Analytics</a><ul>
<li><a href="#受众群体">受众群体</a></li>
<li><a href="#流量获取">流量获取</a></li>
<li><a href="#移动应用">移动应用</a></li>
</ul></li>
<li><a href="#网站性能">网站性能</a><ul>
<li><a href="#网站性能监测">网站性能监测</a></li>
<li><a href="#网站性能-1">网站性能</a></li>
</ul></li>
<li><a href="#seo">SEO</a><ul>
<li><a href="#爬虫与索引">爬虫与索引</a></li>
<li><a href="#什么样的网站需要-seo">什么样的网站需要 SEO?</a></li>
<li><a href="#seo-基础知识">SEO 基础知识</a></li>
<li><a href="#内容">内容</a></li>
</ul></li>
<li><a href="#ux-入门">UX 入门</a><ul>
<li><a href="#什么是-ux">什么是 UX</a></li>
<li><a href="#什么是简单">什么是简单?</a></li>
<li><a href="#进阶">进阶</a></li>
<li><a href="#用户体验要素">用户体验要素</a></li>
</ul></li>
<li><a href="#认知设计">认知设计</a><ul>
<li><a href="#流">流</a></li>
</ul></li>
</ul></li>
<li><a href="#持续交付">持续交付</a><ul>
<li><a href="#持续集成">持续集成</a><ul>
<li><a href="#持续集成系统">持续集成系统</a></li>
<li><a href="#持续集成流程">持续集成流程</a></li>
</ul></li>
<li><a href="#持续交付-1">持续交付</a><ul>
<li><a href="#基础设施">基础设施</a></li>
<li><a href="#持续部署">持续部署</a></li>
</ul></li>
<li><a href="#持续学习">持续学习</a><ul>
<li><a href="#持续阅读">持续阅读</a></li>
<li><a href="#持续编程">持续编程</a></li>
<li><a href="#持续写作">持续写作</a></li>
</ul></li>
</ul></li>
<li><a href="#遗留系统与修改代码">遗留系统与修改代码</a><ul>
<li><a href="#遗留代码">遗留代码</a><ul>
<li><a href="#遗留代码-1">遗留代码</a></li>
</ul></li>
<li><a href="#如何修改遗留代码">如何修改遗留代码</a><ul>
<li><a href="#修改遗留代码">修改遗留代码</a></li>
</ul></li>
<li><a href="#网站重构">网站重构</a><ul>
<li><a href="#速度优化">速度优化</a></li>
<li><a href="#功能加强">功能加强</a></li>
<li><a href="#模块重构">模块重构</a></li>
</ul></li>
</ul></li>
<li><a href="#回顾与架构设计">回顾与架构设计</a><ul>
<li><a href="#自我总结">自我总结</a><ul>
<li><a href="#吾日三省吾身">吾日三省吾身</a></li>
</ul></li>
<li><a href="#retro">Retro</a><ul>
<li><a href="#retro-的过程">Retro 的过程</a></li>
<li><a href="#三个维度">三个维度</a></li>
</ul></li>
<li><a href="#架构模式">架构模式</a><ul>
<li><a href="#预设计式架构">预设计式架构</a></li>
<li><a href="#演进式架构拥抱变化">演进式架构:拥抱变化</a></li>
</ul></li>
<li><a href="#浮现式设计">浮现式设计</a><ul>
<li><a href="#意图导向">意图导向</a></li>
<li><a href="#重构">重构</a></li>
<li><a href="#模式与演进">模式与演进</a></li>
</ul></li>
<li><a href="#每个人都是架构师">每个人都是架构师</a><ul>
<li><a href="#如何构建一个博客系统">如何构建一个博客系统</a></li>
<li><a href="#相关阅读资料">相关阅读资料</a></li>
</ul></li>
<li><a href="#架构解耦">架构解耦</a><ul>
<li><a href="#从-mvc-到微服务">从 MVC 到微服务</a></li>
<li><a href="#cqrs">CQRS</a></li>
<li><a href="#cqrs-结合微服务">CQRS 结合微服务</a></li>
</ul></li>
</ul></li>
</ul>
</nav>
<h1 id="growth-全栈增长工程师指南">Growth: 全栈增长工程师指南</h1>
<h2 id="关于作者">关于作者</h2>
<p>黄峰达(Phodal Huang)是一个创客、工程师、咨询师和作家。他毕业于西安文理学院电子信息工程专业,现作为一个咨询师就职于 ThoughtWorks 深圳。长期活跃于开源软件社区 GitHub,目前专注于物联网和前端领域。</p>
<p>作为一个开源软件作者,著有 Growth、Stepping、Lan、Echoesworks 等软件。其中开源学习应用 Growth,广受读者和用户好评,可在 APP Store 及各大 Android 应用商店下载。</p>
<p>作为一个技术作者,著有《自己动手设计物联网》(电子工业出版社)、《全栈应用开发:精益实践》(电子工业出版社,正在出版)。并在 GitHub 上开源有《Growth: 全栈增长工程师指南》、《GitHub 漫游指南》等七本电子书。</p>
<p>作为技术专家,他为英国 Packt 出版社审阅有物联网书籍《Learning IoT》、《Smart IoT》,前端书籍《Angular 2 Serices》、《Getting started with Angular》等技术书籍。</p>
<p>他热爱编程、写作、设计、旅行、hacking,你可以从他的个人网站:<a href="https://www.phodal.com/" class="uri">https://www.phodal.com/</a> 了解到更多的内容。</p>
<p>其它相关信息:</p>
<ul>
<li>微博:<a href="http://weibo.com/phodal" class="uri">http://weibo.com/phodal</a></li>
<li>GitHub: <a href="https://github.com/phodal" class="uri">https://github.com/phodal</a></li>
<li>知乎:<a href="https://www.zhihu.com/people/phodal" class="uri">https://www.zhihu.com/people/phodal</a></li>
<li>SegmentFault:<a href="https://segmentfault.com/u/phodal" class="uri">https://segmentfault.com/u/phodal</a></li>
</ul>
<p>当前为预览版,在使用的过程中遇到任何问题请及时与我联系。阅读过程中的问题,不妨在GitHub上提出来: <a href="https://github.com/phodal/fe/issues">Issues</a></p>
<p>阅读过程中遇到语法错误、拼写错误、技术错误等等,不妨来个Pull Request,这样可以帮助到其他阅读这本电子书的童鞋。</p>
<p>我的电子书:</p>
<ul>
<li>《<a href="https://github.com/phodal/github-roam">GitHub 漫游指南</a>》</li>
<li>《<a href="https://github.com/phodal/fe">我的职业是前端工程师</a>》</li>
<li>《<a href="https://github.com/phodal/serverless">Serverless 架构应用开发指南</a>》</li>
<li>《<a href="https://github.com/phodal/growth-ebook">Growth: 全栈增长工程师指南</a>》</li>
<li>《<a href="https://github.com/phodal/ideabook">Phodal’s Idea实战指南</a>》</li>
<li>《<a href="https://github.com/phodal/designiot">一步步搭建物联网系统</a>》</li>
<li>《<a href="https://github.com/phodal/repractise">RePractise</a>》</li>
<li>《<a href="https://github.com/phodal/growth-in-action">Growth: 全栈增长工程师实战</a>》</li>
</ul>
<p>我的微信公众号:</p>
<figure>
<img src="assets/article/prelude/wechat.jpg" alt="微信公众号:phodal-weixin" /><figcaption>微信公众号:phodal-weixin</figcaption>
</figure>
<p>支持作者,可以加入作者的小密圈:</p>
<figure>
<img src="assets/article/prelude/xiaomiquan.jpg" alt="小密圈" /><figcaption>小密圈</figcaption>
</figure>
<p>或者转账:</p>
<figure>
<img src="assets/article/prelude/alipay.png" alt="支付宝" /><figcaption>支付宝</figcaption>
</figure>
<figure>
<img src="assets/article/prelude/wechat-pay.png" alt="微信" /><figcaption>微信</figcaption>
</figure>
<p>这是一本不止于全栈工程师的学习手册,它也包含了如何成为一个 Growth Hacker 的知识。</p>
<h2 id="全栈工程师是未来">全栈工程师是未来</h2>
<blockquote>
<p>谨以此文献给每一个为成为优秀全栈工程师奋斗的人。</p>
</blockquote>
<p>技术在过去的几十年里进步很快,也将在未来的几十年里发展得更快。今天技术的门槛下降得越来越快,原本需要一个团队做出来的 Web 应用,现在只需要一两个人就可以了。</p>
<p>同时,由于公司组织结构的变迁,以及到变化的适应度,也决定了赋予每个人的职责将会越来越多。尽管我们看到工厂化生产带来的优势,但是我们也看到了<strong>精益思想</strong>带来的变革。正是这种变革让越来越多的专家走向全栈,让组织内部有更好的交流。</p>
<p>你还将看到专家和全栈的两种不同的学习模式,以及全栈工程师的未来。</p>
<h3 id="技术的革新史">技术的革新史</h3>
<p>从开始的 CGI 到 MVC 模式,再到前后端分离的架构模式,都在不断地降低技术的门槛。而这些门槛的降低,已经足以让一两个人来完成大部分的工作了。</p>
<h4 id="cgi">CGI</h4>
<p>二十年前的网站以静态的形式出现,这样的网站并不需要太多的人去维护、管理。接着,人们发明了 CGI (通用网关接口,英语:Common Gateway Interface)来实现动态的网站。下图是一个早期网站的架构图:</p>
<figure>
<img src="assets/article/prelude/cgi-arch.gif" alt="CGI 网站架构" /><figcaption>CGI 网站架构</figcaption>
</figure>
<p>当时这种网站的URL类似于:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="ex">https</span>://www.phodal.com/cgi-bin/getblog</code></pre></div>
<p>(PS:这个链接是为了讲解而存在的,并没有真实存在。)</p>
<p>用户访问上面的网页的时候就会访问,cgi-bin 的路径下对应的 getblog 脚本。你可以用 Shell 返回这个网页:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="co">#!/bin/sh</span>
<span class="bu">echo</span> Content-type: text/plain
<span class="bu">echo</span> hello,world</code></pre></div>
<p>Blabla,各种代码混乱地夹杂在一起。不得不说一句:这样的代码在2012年,我也看了有一些。简单地来说,这个时代的代码结构就是这样的:</p>
<figure>
<img src="assets/article/prelude/cgi-script.png" alt="CGI脚本文件" /><figcaption>CGI脚本文件</figcaption>
</figure>
<p>这简直就是一场恶梦。不过,在今天好似那些 PHP 新手也是这样写代码的。</p>
<p>好了,这时候我们就可以讨论讨论 MVC 模式了。</p>
<h4 id="mvc架构">MVC架构</h4>
<p>我有理由相信 Martin Fowler 的《企业应用架构模式》在当时一定非常受欢迎。代码从上面的耦合状态变成了:</p>
<figure>
<img src="assets/article/prelude/caf_mvc_arch.png" alt="MVC 架构" /><figcaption>MVC 架构</figcaption>
</figure>
<p>相似大家也已经对这样的架构很熟悉了,我们就不多解释了。如果你还不是非常了解的话,可以看看这本书后面的部分。</p>
<h4 id="后台服务化与前端一致化架构">后台服务化与前端一致化架构</h4>
<p>在今天看来,我们可以看到如下图所示的架构:</p>
<figure>
<img src="assets/article/prelude/oneui-serviceful-arch.png" alt="后台服务化与前台一致化架构" /><figcaption>后台服务化与前台一致化架构</figcaption>
</figure>
<p>后台在不知不觉中已经被服务化了,即只提供API接口和服务。前端在这时已经尽量地和 APP 端在结合,使得他们可以保持一致。</p>
<h3 id="软件开发的核心难题沟通">软件开发的核心难题:沟通</h3>
<p>软件开发在过去的几十年里都是大公司的专利,小公司根本没有足够的能力去做这样的事。在计算机发明后的几十年里,开发软件是大公司才能做得起的。一般的非技术公司无法定制自己的软件系统,只能去购买现有的软件。而随着技术成本的下降,到了今天一般的小公司也可以雇佣一两个人来做同样的事。这样的演进过程还真是有意思:</p>
<figure>
<img src="assets/article/prelude/develop-history.png" alt="开发演进" /><figcaption>开发演进</figcaption>
</figure>
<p>在这其中的每一个过程实质上都是为了解决沟通的问题。从瀑布到敏捷是为了解决组织内沟通的问题,从敏捷到精益不仅仅优化了组织内的沟通问题,还强化了与外部的关系。换句话说,精益结合了一部分的互联网思维。</p>
<h4 id="瀑布式">瀑布式</h4>
<p>在最开始的时候,我们预先设计好我们的功能,然后编码,在适当的时候发布我们的软件:</p>
<figure>
<img src="assets/article/prelude/old-se.jpg" alt="预先式设计的瀑布流" /><figcaption>预先式设计的瀑布流</figcaption>
</figure>
<p>然而这种开发方式很难应对市场的变化——当我们花费了几年的时间开发出了一个软件,而这个软件是几年前人们才需要的。同时,由于软件开发本身的复杂度的限制,复制的系统在后期需要大量的系统集成工作。这样的集成工作可能要花费上大量的时间——几星期、几个月。</p>
<figure>
<img src="assets/article/prelude/waterfall-process.png" alt="瀑布流的沟通模型" /><figcaption>瀑布流的沟通模型</figcaption>
</figure>
<p>当人们意识到这个问题的时候,开始改进工作流程。出现了敏捷软件开发,这可以解释为什么产品经理会经常改需求。如果一个功能本身是没必要出现的话,那么为什么要花功夫去开发。但是如果一个功能在设计的初期就没有好好设计,那么改需求也是必然的。</p>
<h4 id="敏捷式">敏捷式</h4>
<p>现有的互联网公司的工作流程和敏捷软件开发在很多部分上是相似的,都有迭代、分析等等的过程:</p>
<figure>
<img src="assets/article/prelude/scrum.png" alt="敏捷软件开发" /><figcaption>敏捷软件开发</figcaption>
</figure>
<p>但是据我的所知:国内的多数互联网公司是不写测试的、没有 Code Review 等等。当然,这也不是一篇关于如何实践敏捷的文章。敏捷与瀑布式开发在很大的区别就是:沟通问题。传统的软件开发在调研完毕后就是分析、开发等等。而敏捷开发则会强调这个过程中的沟通问题:</p>
<figure>
<img src="assets/article/prelude/scrum-communication.png" alt="敏捷软件开发的沟通模型" /><figcaption>敏捷软件开发的沟通模型</figcaption>
</figure>
<p>在整个过程中都不断地强调沟通问题,然而这时还存在一个问题:组织结构本身的问题。这样的组织结构,如下图所示:</p>
<figure>
<img src="assets/article/prelude/scrum-issues.png" alt="组织结构" /><figcaption>组织结构</figcaption>
</figure>
<p>如果市场部门/产品经理没有与研发团队坐一起来分析问题,那么问题就多了。当一个需求在实现的过程中遇到问题,到底是哪个部门的问题?</p>
<p>同样的如果我们的研发部门是这样子的结构:</p>
<figure>
<img src="assets/article/prelude/tech-org.png" alt="研发部门" /><figcaption>研发部门</figcaption>
</figure>
<p>那么在研发、上线的过程中仍然会遇到各种的沟通问题。</p>
<p>现在,让我们回过头来看看大公司的专家与小公司的全栈。</p>
<h3 id="大公司的专家与小公司的全栈">大公司的专家与小公司的全栈</h3>
<p>如果你经常看一些关于全栈和专家的技术文章的时候,你就会发现不同的人在强调不同的方向。大公司的文章喜欢强调成为某个领域的专家,小公司喜欢小而美的团队——全栈工程师。</p>
<p>如我们所见的:大公司和小公司都在解决不同类型的问题。大公司要解决性能问题,小公司要活下去需要依赖于近乎全能的人。并且,大公司和小公司都在加班。如果从这种意义上来说,我们可以发现其实大公司是在剥削劳动力。</p>
<p><strong>专家</strong></p>
<p>我们所见到的那些关于技术人员应该成为专家的文章,多数是已经成为某个技术领域里的专家写的文章。并且我们可以发现很有意思的一点是:他们都是<strong>管理者</strong>。管理者出于招聘的动机,因此更需要细分领域的专家来帮助他们解决问题。</p>
<p><strong>全栈</strong></p>
<p>相似的,我们所看到的那些关于成为全栈工程师的文章,多数是初创公司的 CTO 写的。而这些初创公司的 CTO 也多数是全栈工程师,他们需要招聘全栈工程师来帮助他们解决问题。</p>
<h4 id="两种不同的学习模型">两种不同的学习模型</h4>
<p>而不知你是否也注意到一点:专家们也在强调<strong>“一专多长”</strong>。因为单纯依靠于一个领域的技术而存在的专家已经很少了,技术专家们不得不依据于公司的需求去开拓不同的领域。毕竟“公司是指全部资本由股东出资构成,以营利为目的而依法设立的一种企业组织形式;”,管理人们假设技术本身是相通的,既然你在技术领域里有相当高的长板,那么进入一个新的技术也不是一件难事。</p>
<p>作为一个技术人员,我们是这个领域中的某个子领域专家。而作为这样一个专家,我们要扩展向另外一个领域的学习也不是一件很难的事。借鉴于我们先前的学习经验,我们可以很快的掌握这个新子域的知识。如我们所见,我们可以很快地补齐图中的短板:</p>
<figure>
<img src="assets/article/prelude/bucket.jpg" alt="木桶" /><figcaption>木桶</figcaption>
</figure>
<p>在近来的探索中发现有一点非常有意思:如果依赖于20/80法则的话,那么成为专家和全栈的学习时间是相当的。在最开始的时候,我们要在我们的全栈工程和专家都在某个技术领域达到80分的水平。</p>
<p>那么专家,还需要80%的时间去深入这个技术领域。而全栈工程师,则可以依赖于这80%的时候去开拓四个新的领域:</p>
<figure>
<img src="assets/article/prelude/expert-vs-fullstack.png" alt="全栈与专家学习时间" /><figcaption>全栈与专家学习时间</figcaption>
</figure>
<p>尽管理论上是如此,但是专家存在跨领域的学习障碍——套用现有模式。而全栈也存在学习障碍——如何成为专家,但是懂得如何学习新的领域。</p>
<h4 id="解决问题的思路不同的方式">解决问题的思路:不同的方式</h4>
<p>有意思的是——成为专家还是成为全栈,取决于人的天性,这也是两种不同的性格决定的。成为管理者还是技术人员看上去就像一种简单的划分,而在技术人员里成为专家还是全栈就是另外一种划分。这取决于人们对于一个问题的思考方式:这件事情是借由外部来解决,还是由内部解决。下面这张图刚好可以表达我的想法:</p>
<figure>
<img src="assets/article/prelude/in-out-thinking.jpeg" alt="内向与外向思维" /><figcaption>内向与外向思维</figcaption>
</figure>
<p>而这种思维依据于不同的事情可能会发生一些差异,但是总体上来说是相似的。当遇到一个需要创轮子的问题时,我们就会看到两种不同的方式。</p>
<p>对于全栈工程师来说,他们喜欢依赖于外部的思维,用于产生颠覆式思维。如 AngularJS 这样的框架便是例子,前端结合后端开发语言 Java 的思维而产生。而专家则依赖于内部的条件,创造出不一样的适应式创新。如之前流行的 Backbone 框架,适应当时的情况而产生。</p>
<h3 id="全栈工程师的未来无栈">全栈工程师的未来:无栈</h3>
<p>全栈工程师本身不应该仅仅局限于前端和后台的开发,而可以尝试去开拓更广泛的领域——因为全栈本身是依赖于工程师本身的学习能力,正是这种优秀的学习能力可以让他们接触更广泛的知识。</p>
<h4 id="全栈的短板">全栈的短板</h4>
<p>如果你也尝试过面试过全栈工程师,你会怎么去面试他们呢?把你知道的所有的不同领域的问题都拿出来问一遍。是的,这就是那些招聘全栈工程师的公司会问你的问题。</p>
<p>人们以为全栈工程师什么都会,这是一个明显的误区——然而要改变这个误区很难。最后,导致的结果是大家觉得全栈工程师的水平也就那样。换句来说,人们根本不知道什么是全栈工程师。在平时的工作里,你的队伍都知道你在不同领域有丰富的知识。而在那些不了解你的人的印象里,就是猜测你什么都会。</p>
<p>因此,这就会变成一个骂名,也是一个在目前看来很难改变的问题。在这方面只能尽可能地去了解一些通用的问题,并不能去了解所有的问题。在一次被面试全栈工程师的过程中,有一个面试官准备了几个不同语言(JavaScript、Java、Python、Ruby)的问题来问我,我只想说 Ciao —— 意大利语:你好!</p>
<p>除了这个问题——人们不了解什么是全栈工程师。还有一个问题,就是刚才我们说的成为专家的老大难问题。</p>
<h4 id="无栈">无栈</h4>
<p>让我毫不犹豫地选择当全栈工程师有两个原因:</p>
<ol type="1">
<li>这个世界充满了未解的迷,但是我只想解开我感兴趣的部分。</li>
<li>没有探索,哪来的真爱?你都没有探索过世界,你就说这是你最喜欢的领域。</li>
</ol>
<p>当我第一次看到全栈工程师这个名字的时候,我发现我已然是一个全栈工程师。因为我的学习路线比较独特:</p>
<ul>
<li>中小学,因为比赛,开始学习编程</li>
<li>高中,因为兴趣,开始学习操作系统内核设计以及游戏编程</li>
<li>大学,因为专业走向硬件的道路,因为生活拮据,用Web开发来赚钱</li>
<li>工作:主要工作领域便是:Java后端、前后端分离、SPA前端,业余还写写APP、游戏、写作</li>
</ul>
<p>而在当时我对 SEO 非常感兴趣,我发现这分析和 Marketing 似乎做得还可以。然后便往 Growth Hacking 发展了:</p>
<figure>
<img src="assets/article/prelude/growth-hacking.jpg" alt="Growth Hacking" /><figcaption>Growth Hacking</figcaption>
</figure>
<p>而这就是全栈学习带来的优势,学过的东西多,学习能力就变强。学习能力往上提的同时,你就更容易进入一个新的领域。</p>
<p>参考书籍</p>
<ul>
<li>《精益企业: 高效能组织如何规模化创新》</li>
<li>《企业应用架构模式》</li>
<li>《敏捷软件开发》</li>
<li>《技术的本质》</li>
</ul>
<h1 id="基础知识篇">基础知识篇</h1>
<p>在我们第一次开始写程序的时候,都是以 Hello World 开始的。或者:</p>
<div class="sourceCode"><pre class="sourceCode c"><code class="sourceCode c">printf(<span class="st">"hello,world"</span>);</code></pre></div>
<p>又或许:</p>
<div class="sourceCode"><pre class="sourceCode javascript"><code class="sourceCode javascript"><span class="at">alert</span>(<span class="st">'hello,world'</span>)<span class="op">;</span></code></pre></div>
<p>过去的十几年里,试过用二十几种不同的语言,每个都是以 hello,world 作为开头。在一些特定的软件,如 Nginx,则是 <strong>It Works</strong>。</p>
<p>这是一个很长的故事,这个程序最早出现于1972年,由贝尔实验室成员布莱恩·柯林汉撰写的内部技术文件《A Tutorial Introduction to the Language B》之中。不久,同作者于1974年所撰写的《Programming in C: A Tutorial》,也延用这个范例;而以本文件扩编改写的《C语言程序设计》也保留了这个范例程式。工作时,我们也会使用类似于 hello,world 的 boilerplate 来完成基本的项目创建。</p>
<p>同时需要注意的一点是,在每个大的项目开始之前我们应该去找寻好开发环境。搭建环境是一件非常重要的事,它决定了你能不能更好地工作。毕竟环境是生产率的一部分。高效的程序员和低效程序员间的十倍差距,至少有三倍是因为环境差异。</p>
<p>因此在这一章里,我们将讲述几件事情:</p>
<ol type="1">
<li>使用怎样的操作系统</li>
<li>如何去选择工具</li>
<li>如何搭建相应操作系统上的环境</li>
<li>如何去学习一门语言</li>
</ol>
<h2 id="工具只是辅助">工具只是辅助</h2>
<p>一个好的工具确实有助于编程,但是他只会给我们带来的是帮助。我们写出来的代码还是和我们的水平保持着一致的。</p>
<p>什么是好的工具,这个说法就有很多了,但是有时候我们往往沉迷于事物的表面。有些时候 Vim 会比 Visual Studio 强大,当你只需要修改的是一个配置文件的时候,简单且足够快捷——在我们还未用 VS 打开的时候,我们已经用 Vim 做完这个活了。</p>
<blockquote>
<p>“好的装备确实能带来一些帮助,但事实是,你的演奏水平是由你自己的手指决定的。” – 《REWORK》</p>
</blockquote>
<h3 id="webstorm-还是-sublime">WebStorm 还是 Sublime?</h3>
<p>作为一个 IDE 有时候忽略的因素会过多,一开始的代码由类似于 Sublime text 之类的编辑器开始会比较合适。于是我们又开始陷入 IDE 及 Editor 之战了,无聊的时候讨论一下这些东西是有点益处的。相互了解一下各自的优点,也是不错的,偶尔可以换个环境试试。</p>
<p>刚开始学习的时候,我们只需要普通的工具,或者我们习惯了的工具去开始我们的工作。我们要的是把主要精力放在学习的东西上,而不是工具。刚开始学习一种新的语言的时候,我们不需要去讨论哪个是最好的开发工具,如 Java,有时候可能是 Eclipse,有时候可能是 Vim,如果我们为的只是去写一个 hello,world。在 Eclipse 上浪费太多的时间是不可取的,因为他用起来的效率可不比你在键盘上敲打来得快,当你移动你的手指去动你的鼠标的时候,我想你可以用那短短的时间完成编译,运行了。</p>
<h4 id="工具是为了效率">工具是为了效率</h4>
<p>寻找工具的目的和寻找捷径是一样的,我们需要更快更有效率地完成我们的工作,换句话说,我们为了获取更多的时间用于其他的事情。而这个工具的用途是要看具体的事物的,如果我们去写一个小说、博客的时候,word 或者 web editor 会比 tex studio 来得快,不是么。我们用 TEX 来排版的时候会比我们用 WORD 排版的时候来得更快,所以这个工具是相对而论的。有时候用一个顺手的工具会好很多,但是不一定会是事半功倍的。我们应该将我们的目标专注于我们的内容,而不是我们的工具上。</p>
<p>我们用 Windows 自带的画图就可以完成裁剪的时候,我们就没必要运行起 GIMP 或者 Photoshop 去完成这个简单的任务。效率在某些时候的重要性,会比你选择的工具有用得多,学习的开始就是要去了解那些大众推崇的东西。</p>
<h4 id="了解熟悉你的工具">了解、熟悉你的工具</h4>
<p>Windows 的功能很强大,只是大部分人用的是只是小小一部分。而不是一小部分,即使我们天天用着,我们也没有学习到什么新的东西。和这个就如同我们的工具一样,我们天天用着他们,如果我们只用 Word 来写写东西,那么我们可以用 Abiword 来替换他。但是明显不太可能,因为强大的工具对于我们来说有些更大的吸引力。</p>
<p>如果你负担得起你手上的工具的话,那么就尽可能去了解他能干什么。即使他是一些无关仅要的功能,比如 Emacs 的煮咖啡。有一本手册是最好不过的,手册在手边可以即时查阅,不过出于环保的情况下,就不是这样子的。手册没有办法即时同你的软件一样更新,电子版的更新会比你手上用的那个手册更新得更快。</p>
<p>Linux 下面的命令有一大堆,只是我们常用的只有一小部分——20%的命令能够完成80%的工作。如同 CISC 和 RISC 一样,我们所常用的指令会让我们忘却那些不常用的指令。而那些是最实用的,如同我们日常工作中使用的 Linux 一样,记忆过多的不实用的东西,不比把他们记在笔记上实在。我们只需要了解有那些功能,如何去用他。</p>
<h3 id="语言也是一种工具">语言也是一种工具</h3>
<p>越来越多的框架和语言出现、更新得越来越快。特别是这样一个高速发展的产业,每天都在涌现新的名词。如同我们选择语言一样,选择合适的有时候会比选得顺手的来得重要。然而,这个可以不断地被推翻。</p>
<p>当我们熟悉用 Python、Ruby、PHP 等去构建一个网站的时候,JavaScript 用来做网站后台,这怎么可能——于是 Node.js 火了。选择工具本身是一件很有趣的事,因为有着越来越多的可能性。</p>
<p>过去 PHP 是主流的开发,不过现在也是,PHP 为 WEB 而生。有一天 Ruby on Rails 出现了,一切就变了,变得高效,变得更 Powerful。MVC 一直很不错,不是么?于是越来越多的框架出现了,如 Django,Laravel 等等。不同的语言有着不同的框架,JavaScript 上也有着合适的框架,如 AngularJS。不同语言的使用者们用着他们合适的工具,因为学习新的东西,对于多数的人来说就是一种新的挑战。在学面向对象语言的时候,人们很容易把程序写成过程式的。</p>
<p>没有合适的工具,要么创造一个,要么选择一个合适的。</p>
<h4 id="小结">小结</h4>
<p>学习 Django 的时候习惯了有一个后台,于是开始使用 Laravel 的时候,寻找 Administartor。需要编译的时候习惯用 IDE,不需要的时候用 Editor,只是因为有效率,嵌入式的时候 IDE 会有效率一点。</p>
<p>以前不知道 WebStorm 的时候,习惯用 DW 来格式化 HTML,Aptana 来格式化 JavaScript。</p>
<p>以前,习惯用 WordPress 来写博客,因为可以有移动客户端,使用电脑时就不喜欢打开浏览器去写。</p>
<p>等等</p>
<p>等</p>
<h2 id="提高效率的工具">提高效率的工具</h2>
<p>在提高效率的 N 种方法里:有一个很重要的方法是使用快捷键。熟练掌握快捷键可以让我们随着自己的感觉编写程序——有时候如果我们手感不好,是不是就说明今天不适合写代码!笑~~</p>
<p>由于我们可能使用不同的操作系统来完成不同的工具。下面就先说说一些通用的、不限操作的工具:</p>
<h3 id="快速启动软件">快速启动软件</h3>
<p>在我还不和道有这样的工具的时候,我都是把图标放在下面的任务栏里:</p>
<figure>
<img src="assets/article/chapter1/windows-launch.png" alt="Windows任务栏" /><figcaption>Windows任务栏</figcaption>
</figure>
<p>直到有一天,我知道有这样的工具。这里不得不提到一本书《卓有成效的程序员》,在书中提到了很多提高效率的工具。使用快捷键是其中的一个,而还有一个是使用快速启动软件。于是,我在 Windows 上使用了 Launcy:</p>
<figure>
<img src="assets/article/chapter1/launchy.png" alt="Launchy" /><figcaption>Launchy</figcaption>
</figure>
<p>通过这个软件,我们可以在电脑上通过输入软件名,然后运行相关的软件。我们不再需要点击某个菜单,再从菜单里选中某个软件打开。</p>
<h3 id="ide">IDE</h3>
<p>尽管在上一篇中,我们说过 IDE 和编辑器没有什么好争论的。但是如果是从头开始搭建环境的话,IDE 是最好的——编辑器还需要安装相应的插件。所以,这也就是为什么面试的时候会用编辑器的原因。</p>
<p>IDE 的全称是集成开发环境,顾名思义即它集成了你需要用到的一些工具。而如果是编辑器的话,你需要自己去找寻合适的工具来做这件事。不过,这也意味着使用编辑器会有更多的自由度。如果你没有足够的时间去打造自己的开发环境就使用 IDE 吧。</p>
<p>一般来说,他们都应该有下面的一些要素:</p>
<ul>
<li><strong>shortcut(快捷键)</strong></li>
<li><strong>Code HighLight(代码高亮)</strong></li>
<li><strong>Auto Complete(自动补全)</strong></li>
<li><strong>Syntax Check(语法检查)</strong></li>
</ul>
<p>而如果是编辑器的话,就需要自己去找寻这些相应的插件。</p>
<p>IDE 一般是针对特定语言才产生的,并且优化更好。而,编辑器则需要自己去搭配。这也意味着如果你需要在多个语言上工作时,并且喜欢折腾,你可以考虑使用编辑器。</p>
<h3 id="debug-工具">DEBUG 工具</h3>
<p>不得不提及的是在有些 IDE 自带了 Debug 工具,这点可能使得使用 IDE 更有优势。在简单的项目里,我们可能不需要这样的 Debug 工具。因为我们对我们的代码库比较熟悉,一个简单的问题一眼就知道是哪里的问题。而对于那些复杂的项目来说,可能就没有那么简单了。特别是当你来到一个新的大中型项目,一个简单的逻辑在实现上可能要经过一系列的函数才能处理完。</p>
<p>这时候我们就需要 Debug 工具——对于前端开发来说,我们可能使用 Chrome 的 Dev Tools。但是对于后端来说,我们就需要使用别的工具。如下图所示的是 Intellij Idea 的 Debug 界面:</p>
<figure>
<img src="assets/article/chapter1/idea-debug.png" alt="Intellij Idea Debug" /><figcaption>Intellij Idea Debug</figcaption>
</figure>
<p>在 Debug 的过程中,我们可以根据代码的执行流程一步步向下执行。这也意味着,当出现 Bug 的时候我们可以更容易找到 Bug。这就是为什么他叫 Debug 工具的原因了。</p>
<h3 id="终端或命令提示符">终端或命令提示符</h3>
<p>在开始写代码的时候,使用 GUI 可能是难以戒掉的一个习惯。但是当你习惯了使用终端之后,或者说使用终端的工具,你会发现这是另外一片天空。对于 GUI 应用上同样的菜单来说,在终端上也会有同样的工具——只是你觉得记住更多的命令。而且不同的工具对于同一实现可能会不同的规范,而 GUI 应用则会有一致的风格。不过,总的来说使用终端是一个很有益的习惯——从速度、便捷性。忘了提到一点,当你使用 Linux 服务器的时候,你不得不使用终端。</p>
<figure>
<img src="assets/article/chapter1/linux-server-console.jpg" alt="Linux 终端截图" /><figcaption>Linux 终端截图</figcaption>
</figure>
<p>使用终端的优点在于我们可以摆脱鼠标的操作——这可以让我们更容易集中精力于完成任务。而这也是两种不同的选择,便捷还是更快。虽是如此,但是这也意味着学习 Linux 会越来越轻松。</p>
<figure>
<img src="assets/article/chapter1/linux-learn-line.png" alt="Linux 与 Windows 的学习曲线" /><figcaption>Linux 与 Windows 的学习曲线</figcaption>
</figure>
<p>虽然这是以 Linux 和 Windows 作了两个不同的对比,但是两个系统在终端工具上的差距是很大的。Linux 自身的哲学鼓励使用命令行来完成任务,这也意味着在 Linux 上会有更多的工具可以在命令行下使用。虽然 Windows 上也可以——如使用 CygWin 来完成,但是这看上去并不是那么让人满意!</p>
<h3 id="包管理">包管理</h3>
<p>虽然包管理不仅仅存在于操作系统中,还存在着语言的包管理工具。在操作系统中安装软件,最方便的东西莫过于包管理了。引自 OpenSUSE 官网的说明及图片:</p>
<figure>
<img src="assets/article/chapter1/pm.png" alt="包管理" /><figcaption>包管理</figcaption>
</figure>
<p>Linux 发行版无非就是一堆软件包 (package) 形式的应用程序加上整体地管理这些应用程序的工具。通常这些 Linux 发行版,包括 OpenSUSE,都是由成千上万不同的软件包构成的。</p>
<ul>
<li><p>软件包: 软件包不止是一个文件,内含构成软件的所有文件,包括程序本身、共享库、开发包以及使用说明等。</p></li>
<li><p>元数据 (metadata) 包含于软件包之中,包含软件正常运行所需要的一些信息。软件包安装之后,其元数据就存储于本地的软件包数据库之中,以用于软件包检索。</p></li>
<li><p>依赖关系 (dependencies) 是软件包管理的一个重要方面。实际上每个软件包都会涉及到其他的软件包,软件包里程序的运行需要有一个可执行的环境(要求有其他的程序、库等),软件包依赖关系正是用来描述这种关系的。</p></li>
</ul>
<p>我们经常会使用各式各样的包管理工具,来加速我们地日常使用。而不是 Google 某个软件,然后下载,接着安装。</p>
<h2 id="环境搭建">环境搭建</h2>
<p>由于我近期工作在 Mac OS X 上,所以先以 Mac OS X 为例。</p>
<h3 id="os-x">OS X</h3>
<p><strong><a href="http://brew.sh/">Homebrew</a></strong></p>
<blockquote>
<p>包管理工具,官方称之为 The missing package manager for OS X。</p>
</blockquote>
<p><strong><a href="https://caskroom.github.io/">Homebrew Cask</a></strong></p>
<blockquote>
<p>brew-cask 允许你使用命令行安装 OS X 应用。</p>
</blockquote>
<p><strong><a href="https://www.iterm2.com/">iTerm2</a></strong></p>
<blockquote>
<p>iTerm2 是最常用的终端应用,是 Terminal 应用的替代品。</p>
</blockquote>
<p><strong><a href="http://www.zsh.org/">Zsh</a></strong></p>
<p>Zsh 是一款功能强大终端(shell)软件,既可以作为一个交互式终端,也可以作为一个脚本解释器。它在兼容 Bash 的同时 (默认不兼容,除非设置成 emulate sh) 还有提供了很多改进,例如:</p>
<ul>
<li>更高效</li>
<li>更好的自动补全</li>
<li>更好的文件名展开(通配符展开)</li>
<li>更好的数组处理</li>
<li>可定制性高</li>
</ul>
<p><strong><a href="http://ohmyz.sh/">Oh My Zsh</a></strong></p>
<blockquote>
<p>Oh My Zsh 同时提供一套插件和工具,可以简化命令行操作。</p>
</blockquote>
<p><strong><a href="https://www.sublimetext.com/">Sublime Text 2</a></strong></p>
<blockquote>
<p>强大的文件编辑器。</p>
</blockquote>
<p><strong><a href="http://macdown.uranusjr.com/">MacDown</a></strong></p>
<blockquote>
<p>MacDown 是 Markdown 编辑器。</p>
</blockquote>
<p><strong><a href="https://www.mediaatelier.com/CheatSheet/">CheatSheet</a></strong></p>
<blockquote>
<p>CheatSheet 能够显示当前程序的快捷键列表,默认的快捷键是长按⌘。</p>
</blockquote>
<p><strong><a href="https://www.sourcetreeapp.com/">SourceTree</a></strong></p>
<blockquote>
<p>SourceTree 是 Atlassian 公司出品的一款优秀的 Git 图形化客户端。</p>
</blockquote>
<p><strong><a href="https://www.alfredapp.com/">Alfred</a></strong></p>
<blockquote>
<p>Mac 用户不用鼠标键盘的必备神器,配合大量 Workflows,习惯之后可以大大减少操作时间。</p>
</blockquote>
<p>上手简单,调教成本在后期自定义 Workflows,不过有大量雷锋使用者提供的现成扩展,访问这里挑选喜欢的,并可以极其简单地根据自己的需要修改。</p>
<p><strong><a href="https://vimium.github.io/">Vimium</a></strong></p>
<blockquote>
<p>Vimium 是一个 Google Chrome 扩展,让你可以纯键盘操作 Chrome。</p>
</blockquote>
<p>相关参考:</p>
<ul>
<li><a href="https://gist.github.com/erikreagan/3259442">Mac web developer apps</a></li>
<li><a href="https://github.com/macdao/ocds-guide-to-setting-up-mac">强迫症的 Mac 设置指南</a></li>
</ul>
<h3 id="windows">Windows</h3>
<p><strong><a href="https://chocolatey.org/">Chocolatey</a></strong></p>
<blockquote>
<p>Chocolatey 是一个软件包管理工具,类似于 Ubuntu 下面的 apt-get,不过是运行在 Windows 环境下面。</p>
</blockquote>
<p><strong><a href="http://www.getwox.com/">Wox</a></strong></p>
<blockquote>
<p>Wox 是一个高效的快速启动器工具,通过快捷键呼出,然后输入关键字来搜索程序进行快速启动,或者搜索本地硬盘的文件,打开百度、Google 进行搜索,甚至是通过一些插件的功能实现单词翻译、关闭屏幕、查询剪贴板历史、查询编程文档、查询天气等更多功能。它最大的特点是可以支持中文拼音的模糊匹配。</p>
</blockquote>
<p><strong><a href="https://msdn.microsoft.com/en-us/powershell/mt173057.aspx">PowerShell</a></strong></p>
<blockquote>
<p>Windows PowerShell 是微软公司为 Windows 环境所开发的壳程序(shell)及脚本语言技术,采用的是命令行界面。这项全新的技术提供了丰富的控制与自动化的系统管理能力。</p>
</blockquote>
<p><strong><a href="http://cmder.net/">cmder</a></strong></p>
<blockquote>
<p>cmder 把 conemu,msysgit 和 clink 打包在一起,让你无需配置就能使用一个真正干净的 Linux 终端!她甚至还附带了漂亮的 monokai 配色主题。</p>
</blockquote>
<p><strong><a href="http://www.ghisler.com/">Total Commander</a></strong></p>
<blockquote>
<p>Total Commander 是一款应用于 Windows 平台的文件管理器 ,它包含两个并排的窗口,这种设计可以让用户方便地对不同位置的“文件或文件夹”进行操作,例如复制、移动、删除、比较等,相对 Windows 资源管理器而言方便很多,极大地提高了文件操作的效率,被广大软件爱好者亲切地简称为:TC 。</p>
</blockquote>
<h3 id="gnulinux">GNU/Linux</h3>
<p><strong><a href="http://www.zsh.org/">Zsh</a></strong></p>
<p>Zsh 是一款功能强大终端(shell)软件,既可以作为一个交互式终端,也可以作为一个脚本解释器。它在兼容 Bash 的同时 (默认不兼容,除非设置成 emulate sh) 还有提供了很多改进,例如:</p>
<ul>
<li>更高效</li>
<li>更好的自动补全</li>
<li>更好的文件名展开(通配符展开)</li>
<li>更好的数组处理</li>
<li>可定制性高</li>
</ul>
<p><strong><a href="http://ohmyz.sh/">Oh My Zsh</a></strong></p>
<blockquote>
<p>Oh My Zsh 同时提供一套插件和工具,可以简化命令行操作。</p>
</blockquote>
<p><strong><a href="https://github.com/retext-project/retext">ReText</a></strong></p>
<blockquote>
<p>ReText 是一个使用 Markdown 语法和 reStructuredText (reST) 结构的文本编辑器,编辑的内容支持导出到 PDF、ODT 和 HTML 以及纯文本,支持即时预览、网页生成以及 HTML 语法高亮、全屏模式,可导出文件到 Google Docs 等。</p>
</blockquote>
<p><strong><a href="http://www.launchy.net/">Launchy</a></strong></p>
<blockquote>
<p>Launchy 是一款免费开源的协助您摒弃 Windows “运行”的 Dock 式替代工具,既方便又实用,自带多款皮肤,作为美化工具也未尝不可。</p>
</blockquote>
<p>环境搭建完毕!现在,就让我们来看看如何学好一门语言!</p>
<h2 id="学好一门语言的艺术">学好一门语言的艺术</h2>
<h3 id="一次语言学习体验">一次语言学习体验</h3>
<p>在我们开始学习一门语言或者技术的时候,我们可能会从一门 “hello,world” 开始。</p>
<p>好了,现在我是 Scala 语言的初学者,接着我用搜索引擎去搜索『Scala』来看看『Scala』是什么鬼:</p>
<blockquote>
<p>Scala 是一门类 Java 的编程语言,它结合了面向对象编程和函数式编程。</p>
</blockquote>
<p>接着又开始看『Scala ‘hello,world’』,然后找到了这样的一个示例:</p>
<pre><code>object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello, world!")
}
}</code></pre>
<p>GET 到了5%的知识。</p>
<p>看上去这门语言相比于 Java 语言来说还行。然后我找到了一本名为『Scala 指南』的电子书,有这样的一本目录:</p>
<ul>
<li>表达式和值</li>
<li>函数是一等公民</li>
<li>借贷模式</li>
<li>按名称传递参数</li>
<li>定义类</li>
<li>鸭子类型</li>
<li>柯里化</li>
<li>范型</li>
<li>Traits</li>
<li>…</li>
</ul>
<p>看上去还行, 又 GET 到了5%的知识点。接着,依照上面的代码和搭建指南在自己的电脑上安装了 Scala 的环境:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="ex">brew</span> install scala</code></pre></div>
<p>Windows 用户可以用:</p>
<pre><code>choco install scala</code></pre>
<p>然后开始写一个又一个的 Demo,感觉自己 GET 到了很多特别的知识点。</p>
<p>到了第二天忘了!</p>
<figure>
<img src="assets/article/chapter1/wrong.jpg" alt="Bro Wrong" /><figcaption>Bro Wrong</figcaption>
</figure>
<p>接着,你又重新把昨天的知识过了一遍,还是没有多大的作用。突然间,你听到别人在讨论什么是<strong>这个世界上最好的语言</strong>——你开始加入讨论了。</p>
<p>于是,你说出了 Scala 这门语言可以:</p>
<ul>
<li>支持高阶函数。lambda,闭包…</li>
<li>支持偏函数。 match..</li>
<li>mixin,依赖注入..</li>
<li>等等</li>
</ul>
<p>虽然隔壁的 Python 小哥赢得了这次辩论,然而你发现你又回想起了 Scala 的很多特性。</p>
<figure>
<img src="assets/article/chapter1/popular.jpg" alt="最流行的语言" /><figcaption>最流行的语言</figcaption>
</figure>
<p>你发现隔壁的 Python 小哥之所以赢得了这场辩论是因为他把 Python 语言用到了各个地方——机器学习、人工智能、硬件、Web开发、移动应用等。而你还没有用 Scala 写过一个真正的应用。</p>
<p>让我想想我能做什么?我有一个博客。对,我有一个博客,可以用 Scala 把我的博客重写一遍:</p>
<ol type="1">
<li>先找一 Scala 的 Web 框架,Play 看上去很不错,就这个了。这是一个 MVC 框架,原来用的 Express 也是一个 MVC 框架。Router 写这里,Controller 类似这个,就是这样的。</li>
<li>既然已经有 PyJS,也会有 Scala-js,前端就用这个了。</li>
</ol>
<p>好了,博客重写了一遍了。</p>
<p>感觉还挺不错的,我决定向隔壁的 Java 小弟推销这门语言,以解救他于火海之中。</p>
<p>『让我想想我有什么杀手锏?』</p>
<p>『这里的知识好像还缺了一点,这个是什么?』</p>
<p>好了,你已经 GET 到了90%了。如下图所示:</p>
<figure>
<img src="assets/article/chapter1/learn.jpg" alt="Learn" /><figcaption>Learn</figcaption>
</figure>
<p>希望你能从这张图上 GET 到很多点。</p>
<h3 id="输出是最好的输入">输出是最好的输入</h3>
<p>上面那张图『学习金字塔』就是在说明——输出是最好的输入。</p>
<p>如果你不试着去写点博客、整理资料、准备分享,那么你可能并没有意识到你缺少了多少东西。虽然你已经有了很多的实践,然并卵。</p>
<p>因为你一直在完成功能、完成工作,你总会有意、无意地漏掉一些知识,而你也没有意识到这些知识的重要性。</p>
<figure>
<img src="assets/article/chapter1/output-input.png" alt="Output is Input" /><figcaption>Output is Input</figcaption>
</figure>
<p>从我有限的(500+)博客写作经验里,我发现多数时候我需要更多地参考资料才能更好也向人们展示这个过程。为了输出我们需要更多的输入,进而加速这个过程。</p>
<p>而如果是写书的时候则是一个更高水平的学习,你需要发现别人在他们的书中欠缺的一些知识点。并且你还要展示一些在别的书中没有,而这本书会展现这个点的知识,这意味着你需要挖掘得更深。</p>
<p>所以,如果下次有人问你如何学一门新语言、技术,那么答案就是写一本书。</p>
<h3 id="如何应用一门新的技术">如何应用一门新的技术</h3>
<p>对于多数人来说,写书不是一件容易的事,而应用新的技术则是一件迫在眉睫的事。</p>
<p>通常来说,技术出自于对现有的技术的改进。这就意味着,在掌握现有技术的情况下,我们只需要做一些小小的改动就更可以实现技术升级。</p>
<p>而学习一门新的技术的最好实践就是用这门技术对现有的系统行重写。</p>
<p>第一个系统(v1): <code>Spring MVC</code> + <code>Bootstrap</code> + <code>jQuery</code></p>
<p>那么在那个合适的年代里, 我们需要单页面应用,就使用了Backbone。然后,我们就可以用 Mustache + HTML 来替换掉 JSP。</p>
<p>第二个系统(v2): <code>Spring MVC</code> + <code>Backbone</code> + <code>Mustache</code></p>
<p>在这时我们已经实现了前后端分离了,这时候系统实现上变成了这样。</p>
<p>第二个系统(v2.2): <code>RESTful Services</code> + <code>Backbone</code> + <code>Mustache</code></p>
<p>或者</p>
<p>第二个系统(v2.2): <code>RESTful Services</code> + <code>AngularJS 1.x</code></p>
<p>Spring 只是一个 RESTful 服务,我们还需要一些问题,比如 DOM 的渲染速度太慢了。</p>
<p>第三个系统(v3): <code>RESTful Services</code> + <code>React</code></p>
<p>系统就是这样一步步演进过来的。</p>
<p>尽管在最后系统的架构已经不是当初的架构,而系统本身的业务逻辑变化并没有发生太大的变化。</p>
<p>特别是对于如博客这一类的系统来说,他的一些技术实现已经趋于稳定,而且是你经常使用的东西。所以,下次试试用新的技术的时候,可以先从对你的博客的重写开始。</p>
<h2 id="web-编程基础">Web 编程基础</h2>
<h3 id="从浏览器到服务器">从浏览器到服务器</h3>
<p>如果你的操作系统带有 cURL 这个软件(在 GNU/Linux、Mac OS 都自带这个工具,Windows 用户可以从<a href="http://curl.haxx.se/download.html" class="uri">http://curl.haxx.se/download.html</a>下载到),那么我们可以直接用下面的命令来看这看这个过程(-v 参数可以显示一次 http 通信的整个过程):</p>
<pre><code>curl -v https://www.phodal.com</code></pre>
<p>我们就会看到下面的响应过程:</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="ex">*</span> Rebuilt URL to: https://www.phodal.com/
<span class="ex">*</span> Trying 54.69.23.11...
<span class="ex">*</span> Connected to www.phodal.com (54.69.23.11) <span class="ex">port</span> 443 (#0)
<span class="ex">*</span> TLS 1.2 connection using TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
<span class="ex">*</span> Server certificate: www.phodal.com
<span class="ex">*</span> Server certificate: COMODO RSA Domain Validation Secure Server CA
<span class="ex">*</span> Server certificate: COMODO RSA Certification Authority
<span class="ex">*</span> Server certificate: AddTrust External CA Root
<span class="op">></span> <span class="ex">GET</span> / HTTP/1.1
<span class="op">></span> <span class="ex">Host</span>: www.phodal.com
<span class="op">></span> <span class="ex">User-Agent</span>: curl/7.43.0
<span class="op">></span> <span class="ex">Accept</span>: */*
<span class="op">></span>
<span class="op"><</span> <span class="ex">HTTP/1.1</span> 403 Forbidden
<span class="op"><</span> <span class="ex">Server</span>: phodal/0.19.4
<span class="op"><</span> <span class="ex">Date</span>: Tue, 13 Oct 2015 05:32:13 GMT
<span class="op"><</span> <span class="ex">Content-Type</span>: text/html<span class="kw">;</span> <span class="va">charset=</span>utf-8
<span class="op"><</span> <span class="ex">Content-Length</span>: 170
<span class="op"><</span> <span class="ex">Connection</span>: keep-alive
<span class="op"><</span>
<span class="op"><</span><span class="ex">html</span><span class="op">></span>
<span class="op"><</span><span class="fu">head</span><span class="op">><</span>title<span class="op">></span>403 Forbidden<span class="op"><</span>/title<span class="op">><</span>/head<span class="op">></span>
<span class="op"><</span><span class="ex">body</span> bgcolor=<span class="st">"white"</span><span class="op">></span>
<span class="op"><</span><span class="ex">center</span><span class="op">><</span>h1<span class="op">></span>403 Forbidden<span class="op"><</span>/h1<span class="op">><</span>/center<span class="op">></span>
<span class="op"><</span><span class="ex">hr</span><span class="op">><</span>center<span class="op">></span>phodal/0.19.<span class="op">4<</span>/center<span class="op">></span>
<span class="op"><</span>/<span class="ex">body</span><span class="op">></span>
<span class="op"><</span>/<span class="ex">html</span><span class="op">></span>
<span class="ex">*</span> Connection <span class="co">#0 to host www.phodal.com left intact</span></code></pre></div>
<p>我们尝试用 cURL 去访问我的网站,会根据访问的域名找出其 IP,通常这个映射关系是来源于 ISP 缓存 DNS(英语:Domain Name System)服务器[^DNSServer]。</p>
<p>以“*”开始的前8行是一些连接相关的信息,称为<strong>响应首部</strong>。我们向域名 <a href="https://www.phodal.com/" class="uri">https://www.phodal.com/</a>发出了请求,接着 DNS服务器告诉了我们网站服务器的 IP,即54.69.23.11。出于安全考虑,在这里我们的示例,我们是以 HTTPS 协议为例,所以在这里连接的端口是 443。因为使用的是 HTTPS 协议,所以在这里会试图去获取服务器证书,接着获取到了域名相关的证书信息。</p>
<p>随后以“>”开始的内容,便是向Web服务器发送请求。Host 即是我们要访问的主机的域名,GET / 则代表着我们要访问的是根目录,如果我们要访问 <a href="https://www.phodal.com/about/" class="uri">https://www.phodal.com/about/</a>页面在这里,便是 GET 资源文件 /about。紧随其后的是 HTTP 的版本号(HTTP/1.1)。User-Agent 通常指向的是使用者行为的软件,通常会加上硬件平台、系统软件、应用软件和用户个人偏好等等的一些信息。Accept 则指的是告知服务器发送何种媒体类型。</p>
<p>这个过程,大致如下图所示:</p>
<figure>
<img src="assets/article/chapter1/server-dns-forward.jpg" alt="DNS 到服务器的过程" /><figcaption>DNS 到服务器的过程</figcaption>
</figure>
<p>在图中,我们会发现解析 DNS 的时候,我们需要先本地 DNS 服务器查询。如果没有的话,再向根域名服务器查询——这个域名由哪个服务器来解析。直至最后拿到真正的服务器IP才能获取页面。</p>
<p>当我们拿到相应的 HTML、JS、CSS 后,我们就开始渲染这个页面了。</p>
<h4 id="http-协议">HTTP 协议</h4>
<p>说到这里,我们不得不说说 HTTP 协议——超文本传输协议。它也是一个基于文本的传输协议,这就是为什么你在上面看到的都是文本的传输过程。</p>
<h3 id="从-html-到页面显示">从 HTML 到页面显示</h3>
<p>而浏览器接收到文本的时候,就要开始着手将 HTML 变成屏幕上显示的内容。下图是 Chrome 渲染页面的一个时间线:</p>
<figure>
<img src="assets/article/chapter1/chrome-timeline.jpg" alt="Chrome 渲染的 Timeline" /><figcaption>Chrome 渲染的 Timeline</figcaption>
</figure>
<p>及其整个渲染过程如下图所示:</p>
<figure>
<img src="assets/article/chapter1/render-html.png" alt="Render HTML" /><figcaption>Render HTML</figcaption>
</figure>
<p>(PS: 需要注意的是这里用的是 WebKit 内核的渲染过程,即 Chrome 和 Safari 等浏览器所使用的内核。)</p>
<p>从上面的两图可以看出来第一步都 Parse HTML,而 Parse HTML 实质上就是将其将解析为 DOM Tree。与此同时,CSS 解析器会解析 CSS 会产生 CSS 规则树。</p>
<p>随后会根据生成的 DOM 树和 CSS 规则树来构建 Render Tree,接着生成 Render Tree的布局,最后就是绘制出 Render Tree。</p>
<p>详细的内容还得参见相关的书籍~~。</p>
<p>相关内容:</p>
<ul>
<li>《<a href="http://taligarsiel.com/Projects/howbrowserswork1.htm">How browsers work</a>》</li>
</ul>
<h2 id="html">HTML</h2>
<p>让我们先从身边的语言下手,也就是现在无处不在的 HTML+Javascript+CSS。</p>
<p>之所以从 HTML 开始,是因为我们不需要配置一个复杂的开发环境,也许你还不知道开发环境是什么东西,不过这也没关系,毕竟这些知识需要慢慢的接触才能有所了解,尤其是对于普通的业余爱好者来说,当然,对于专业选手而言自然不是问题。HTML 是 Web 的核心语言,也算是比较基础的语言。</p>
<h3 id="helloworld">hello,world</h3>
<p>hello,world 是一个传统,所以在这里也遵循这个有趣的传统,我们所要做的事情其实很简单,虽然也有一点点 hack 的感觉。——让我们先来新建一个文件并命名为“helloworld.html”。</p>
<p>(PS:大部分人应该都是在 Windows 环境下工作的,所以你需要新建一个文本,然后重命名,或者你需要一个编辑器,在这里我们推荐用 <strong>Sublime Text</strong> 。破解不破解,注册不注册都不会对你的使用有太多的影响。)</p>
<ol type="1">
<li><p>新建文件</p></li>
<li>输入
<pre><code class="html">hello,world</code></pre></li>
<li><p>保存为->“helloworld.html”,</p></li>
<li><p>双击打开这个文件。 正常情况下都应该是用你的默认浏览器打开。只要是一个正常工作的现代浏览器,都应该可以看到上面显示的是“Hello,world”。</p></li>
</ol>
<p>这才是最短的 hello,world 程序,但是呢?在 Ruby 中会是这样子的</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash"><span class="ex">2.0.0-p353</span> :001 <span class="op">></span> p <span class="st">"hello,world"</span>
<span class="st">"hello,world"</span>
=<span class="op">></span> <span class="st">"hello,world"</span>
<span class="ex">2.0.0-p353</span> :002 <span class="op">></span></code></pre></div>
<p>等等,如果你了解过 HTML 的话,会觉得这一点都不符合语法规则,但是他工作了,没有什么比安装完 Nginx 后看到 It works! 更让人激动了。</p>
<p>遗憾的是,它可能无法在所有的浏览器上工作,所以我们需要去调试其中的 bug。</p>
<h4 id="调试-helloworld">调试 hello,world</h4>
<p>我们会发现我们的代码在浏览器中变成了下面的代码,如果你和我一样用的是 Chrome,那么你可以右键浏览器中的空白区域,点击审查元素,就会看到下面的代码。</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="kw"><html></span>
<span class="kw"><head></head></span>
<span class="kw"><body></span>hello,world<span class="kw"></body></span>
<span class="kw"></html></span></code></pre></div>
<p>这个才是真正能在大部分浏览器上工作的代码,所以复制它到编辑器里吧。</p>
<h4 id="说说-helloworld">说说 hello,world</h4>
<p>我很不喜欢其中的<*></*>,但是我也没有找到别的方法来代替它们,所以这是一个设计得当的语言。甚至大部分人都说这算不上是一门真正的语言,不过 HTML 的原义是</p>
<blockquote>
<p>超文本标记语言</p>
</blockquote>
<p>所以我们可以发现其中的关键词是标记——markup,也就是说 html 是一个 markup,head 是一个 markup,body 也是一个 markup。</p>
<p>然而,我们真正工作的代码是在 body 里面,至于为什么是在这里面,这个问题就太复杂了。打个比方来说:</p>
<ol type="1">
<li><p>我们所使用的汉语是人类用智慧创造的,我们所正在学的这门语言同样也是人类创造的。</p></li>
<li><p>我们在自己的语言里遵循着 <strong>桌子是桌子,凳子是凳子</strong> 的原则,很少有人会问为什么。</p></li>
</ol>
<h3 id="中文">中文?</h3>
<p>所以我们也可以把计算机语言与现实世界里用于交流沟通的语言划上一个等号。而我们所要学习的语言,并不是我们最熟悉的汉语语言,所以我们便觉得这些很复杂,但是如果我们试着用汉语替换掉上面的代码的话</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="er"><</span>语言>
<span class="er"><</span>头><span class="er"><</span>结束头>
<span class="er"><</span>身体>你好,世界<span class="er"><</span>结束身体>
<span class="er"><</span>结束语言></code></pre></div>
<p>这看上去很奇怪,只是因为是直译过去的原因,也许你会觉得这样会好理解一点,但是输入上可就一点儿也不方便,因为这键盘本身就不适合我们去输入汉字,同时也意味着可能你输入的会有问题。</p>
<p>让我们把上面的代码代替掉原来的代码然后保存,打开浏览器会看到下面的结果</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="er"><</span>语言> <span class="er"><</span>头><span class="er"><</span>结束头> <span class="er"><</span>身体>你好,世界<span class="er"><</span>结束身体> <span class="er"><</span>结束语言></code></pre></div>
<p>更不幸的结果可能是</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="er"><</span>璇█> <span class="er"><</span>澶�><span class="er"><</span>缁撴潫澶�> <span class="er"><</span>韬綋>浣犲ソ锛屼笘鐣�<span class="er"><</span>缁撴潫韬綋> <span class="er"><</span>缁撴潫璇█></code></pre></div>
<p>这是一个编码问题,对中文支持不友好。</p>
<p>我们把上面的代码改为和标记语言一样的结构</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="er"><</span>语言>
<span class="er"><</span>头><span class="er"><</span>/头>
<span class="er"><</span>身体>你好,世界<span class="er"><</span>/身体>
<span class="er"><</span>/语言></code></pre></div>
<p>于是我们看到的结果便是</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="er"><</span>语言> <span class="er"><</span>头> <span class="er"><</span>身体>你好,世界</code></pre></div>
<p>被 Chrome 浏览器解析成什么样了?</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="kw"><html><head></head><body></span><span class="er"><</span>语言>
<span class="er"><</span>头><span class="co"><!--头--></span>
<span class="er"><</span>身体>你好,世界<span class="co"><!--身体--></span>
<span class="co"><!--语言--></span>
<span class="kw"></body></html></span> </code></pre></div>
<p>以<code><!--</code>开头,<code>--></code>结尾的是注释,写给人看的代码,不是给机器看的,所以机器不会去理解这些代码。</p>
<p>但是当我们把代码改成</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="kw"><whatwewanttosay></span>你好世界<span class="kw"></whatwewanttosay></span></code></pre></div>
<p>浏览器上面显示的内容就变成了</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html">你好世界</code></pre></div>
<p>或许你会觉得很神奇,但是这一点儿也不神奇,虽然我们的中文语法也遵循着标记语言的标准,但是我们的浏览器不支持中文标记。</p>
<p>结论:</p>
<ol type="1">
<li>浏览器对中文支持不友好。</li>
<li>浏览器对英文支持友好。</li>
</ol>
<p>刚开始的时候不要对中文编程有太多的想法,这是很不现实的:</p>
<ol type="1">
<li>现有的系统都是基于英语语言环境构建的,对中文支持不是很友好。</li>
<li>中文输入的速度在某种程度上来说没有英语快。</li>
</ol>
<p>我们离开话题已经很远了,但是这里说的都是针对于那些不满于英语的人来说的,只有当我们可以从头构建一个中文系统的时候才是可行的,而这些就要将 CPU、软件、硬件都包含在内,甚至我们还需要考虑重新设计 CPU 的结构,在某种程度上来说会有些不现实。或许,需要一代又一代人的努力。忘记那些吧,师夷之长技以制夷。</p>
<h3 id="其它-html-标记">其它 HTML 标记</h3>
<p>添加一个标题,</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="kw"><html></span>
<span class="kw"><head></span>
<span class="kw"><title></span>标题<span class="kw"></title></span>
<span class="kw"></head></span>
<span class="kw"><body></span>hello,world<span class="kw"></body></span>
<span class="kw"></html></span></code></pre></div>
<p>我们便可以在浏览器的最上方看到“标题”二字,就像我们常用的淘宝网,也包含了上面的东西,只是还包括了更多的东西,所以你也可以看懂那些我们可以看到的淘宝的标题。</p>
<div class="sourceCode"><pre class="sourceCode html"><code class="sourceCode html"><span class="kw"><html></span>
<span class="kw"><head></span>
<span class="kw"><title></span>标题<span class="kw"></title></span>
<span class="kw"></head></span>
<span class="kw"><body></span>
hello,world
<span class="kw"><h1></span>大标题<span class="kw"></h1></span>
<span class="kw"><h2></span>次标题<span class="kw"></h2></span>
<span class="kw"><h3></span>...<span class="kw"></h3></span>
<span class="kw"><ul></span>
<span class="kw"><li></span>列表1<span class="kw"></li></span>
<span class="kw"><li></span>列表2<span class="kw"></li></span>
<span class="kw"></ul></span>
<span class="kw"></body></span>
<span class="kw"></html></span></code></pre></div>
<p>更多的东西可以在一些书籍上看到,这边所要说的只是一次简单的语言入门,其它的东西都和这些类似。</p>
<h3 id="小结-1">小结</h3>
<h4 id="美妙之处">美妙之处</h4>
<p>我们简单地上手了一门不算是语言的语言,浏览器简化了这其中的大部分过程,虽然没有 C 和其他语言来得有专业感,但是我们试着去开始写代码了。我们可能在未来的某一篇中可能会看到类似的语言,诸如 Python,我们所要做的就是</p>
<div class="sourceCode"><pre class="sourceCode bash"><code class="sourceCode bash">$ <span class="ex">python</span> file.py
=<span class="op">></span><span class="ex">hello</span>,world</code></pre></div>
<p>然后在终端上返回结果。只是因为在我看来学会 HTML 是有意义的,简单的上手,然后再慢慢地深入,如果一开始我们就去理解指针,开始去理解类。我们甚至还知道程序是怎么编译运行的时候,在这个过程中又发生了什么。虽然现在我们也没能理解这其中发生了什么,但是至少展示了</p>
<ol type="1">
<li>中文编程语言在当前意义不大,不现实,效率不高兼容性差</li>
<li>语言的语法是固定的。(ps:虽然我们也可以进行扩充,我们将会在后来支持上述的中文标记。)</li>
<li>已经开始写代码,而不是还在配置开发环境。</li>