-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathatom.xml
More file actions
1145 lines (884 loc) · 82.8 KB
/
atom.xml
File metadata and controls
1145 lines (884 loc) · 82.8 KB
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
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title><![CDATA[课程格子黑板报]]></title>
<link href="http://creatingev.github.io/atom.xml" rel="self"/>
<link href="http://creatingev.github.io/"/>
<updated>2014-07-28T10:51:58+08:00</updated>
<id>http://creatingev.github.io/</id>
<author>
<name><![CDATA[CreatingEV]]></name>
</author>
<generator uri="http://octopress.org/">Octopress</generator>
<entry>
<title type="html"><![CDATA[Rails_server后边隐藏的真相]]></title>
<link href="http://creatingev.github.io/blog/2014/01/12/rails-serverhou-bian-yin-cang-de-zhen-xiang/"/>
<updated>2014-01-12T01:38:40+08:00</updated>
<id>http://creatingev.github.io/blog/2014/01/12/rails-serverhou-bian-yin-cang-de-zhen-xiang</id>
<content type="html"><![CDATA[<h2>第一部分 Rack</h2>
<h3>什么是rack</h3>
<p>Rack 为开发 Ruby web 应用提供了一个最小的模块化和适应性接口。通过对 HTTP 请求与响应 的尽可能最简单的方式包装,它统一和提炼 Web 服务器 ,Web 框架,和之间的软件(所谓的中间件)的 API 为单一方法调用。</p>
<h3>什么是rack app</h3>
<p>A Rack application is any Ruby object that responds to the call method, takes a single hash parameter and returns an array containing the response status code, HTTP response headers and the response body as an array of strings.</p>
<p>意思就是,一个包含call(env)方法的对象就能做为一个Rack Web应用,参数env是一个hash,方法的返回值是一个列表,包含三个元素:HTTP状态码(200, 500等),HTTP响应头(Hash),HTTP响应内容(字符串数组)。</p>
<h4>一些具体的例子</h4>
<p>simplest.ru</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="c1"># run with rackup</span>
</span><span class='line'><span class="no">Simplest</span> <span class="o">=</span> <span class="nb">proc</span> <span class="p">{</span> <span class="o">|</span><span class="n">env</span><span class="o">|</span> <span class="o">[</span><span class="s2">"200"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"Content-Type"</span> <span class="o">=></span> <span class="s2">"text/plain"</span><span class="p">},</span> <span class="o">[</span><span class="s2">"OK"</span><span class="o">]]</span> <span class="p">}</span>
</span><span class='line'>
</span><span class='line'><span class="n">run</span> <span class="no">Simplest</span>
</span></code></pre></td></tr></table></div></figure>
<p>redirect.rb</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">"rack"</span>
</span><span class='line'>
</span><span class='line'><span class="k">class</span> <span class="nc">Redirect</span>
</span><span class='line'> <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">call</span> <span class="n">env</span>
</span><span class='line'> <span class="k">if</span> <span class="n">env</span><span class="o">[</span><span class="s2">"QUERY_STRING"</span><span class="o">]</span> <span class="o">=~</span> <span class="sr">/url=redirect/</span>
</span><span class='line'> <span class="o">[</span><span class="s2">"302"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"location"</span> <span class="o">=></span> <span class="s2">"http://qhr.me"</span><span class="p">},</span> <span class="o">[]]</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="o">[</span><span class="s2">"200"</span><span class="p">,</span> <span class="p">{</span><span class="s2">"location"</span> <span class="o">=></span> <span class="s2">"text/plain"</span><span class="p">},</span> <span class="o">[</span><span class="s2">"ok"</span><span class="o">]]</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span><span class='line'>
</span><span class='line'><span class="ss">Rack</span><span class="p">:</span><span class="ss">:Server</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">app</span><span class="p">:</span> <span class="no">Redirect</span><span class="p">,</span> <span class="ss">environment</span><span class="p">:</span> <span class="s2">"development"</span><span class="p">)</span><span class="o">.</span><span class="n">start</span>
</span></code></pre></td></tr></table></div></figure>
<p>local_dir.rb</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="nb">require</span> <span class="s2">"rack"</span>
</span><span class='line'>
</span><span class='line'><span class="ss">Rack</span><span class="p">:</span><span class="ss">:Server</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="ss">app</span><span class="p">:</span> <span class="ss">Rack</span><span class="p">:</span><span class="ss">:Directory</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="s2">"~/"</span><span class="p">))</span><span class="o">.</span><span class="n">start</span>
</span></code></pre></td></tr></table></div></figure>
<p>更多的细节请大家参看<a href="http://guides.ruby-china.org/rails_on_rack.html">http://guides.ruby-china.org/rails_on_rack.html</a>这里就不在重复了。</p>
<h2>第二部分 Server (Webrick举例)</h2>
<p>webrick是ruby标准库中的一个webserver。</p>
<h1>一些基础</h1>
<h3>SizedQueue</h3>
<p>一个线程安全的队列,有大小限制。队列为空的时候,pop操作的线程会被阻塞。队列满的时候,push操作的线程会被阻塞。</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="n">q</span> <span class="o">=</span> <span class="no">SizedQueue</span><span class="o">.</span><span class="n">new</span> <span class="mi">1</span>
</span><span class='line'>
</span><span class='line'><span class="n">q</span><span class="o">.</span><span class="n">push</span> <span class="mi">1</span>
</span><span class='line'>
</span><span class='line'><span class="no">Thread</span><span class="o">.</span><span class="n">start</span> <span class="p">{</span>
</span><span class='line'> <span class="kp">loop</span> <span class="k">do</span>
</span><span class='line'> <span class="nb">puts</span> <span class="n">q</span><span class="o">.</span><span class="n">pop</span>
</span><span class='line'> <span class="nb">sleep</span> <span class="mi">10</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="p">}</span>
</span><span class='line'>
</span><span class='line'>
</span><span class='line'><span class="n">q</span><span class="o">.</span><span class="n">push</span> <span class="mi">2</span>
</span><span class='line'><span class="n">q</span><span class="o">.</span><span class="n">push</span> <span class="mi">3</span>
</span></code></pre></td></tr></table></div></figure>
<h3>TCPServer</h3>
<p>TCP/IP stream型连接的服务器端套接字的类。accept实例方法会受理客户端的连接请求, 返回已连接的TCPSocket的实例。</p>
<h3>IO::select</h3>
<p>多路复用IO。参数列表前三项为输入/输出/异常的IO(或者子类)的实例数组。第四个参数是timeout。第四个参数是timeout可以是整数、Float或nil(省略时的默认值)。指定为nil时,将会一直等到IO变成就绪状态。timeout时将返回nil,除此以外将返回一个包含3个元素的数组,这3个元素分别是等待输入/输出/异常的对象的数组(指定数组的子集)。</p>
<h1>从rack开始</h1>
<p>rack可以简单的理解成ruby frameword 和 webserver 之间的一个通用接口。一份基于rack开发的web服务可以使用rack支持的各种server来运行。rack中的所有server都具有一个叫做run的方法,这个是web server的入口。那么从rack/lib/rack/handler/webrick.rb中可以找到如下代码。</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">run</span><span class="p">(</span><span class="n">app</span><span class="p">,</span> <span class="n">options</span><span class="o">=</span><span class="p">{})</span>
</span><span class='line'> <span class="n">environment</span> <span class="o">=</span> <span class="no">ENV</span><span class="o">[</span><span class="s1">'RACK_ENV'</span><span class="o">]</span> <span class="o">||</span> <span class="s1">'development'</span>
</span><span class='line'> <span class="n">default_host</span> <span class="o">=</span> <span class="n">environment</span> <span class="o">==</span> <span class="s1">'development'</span> <span class="p">?</span> <span class="s1">'localhost'</span> <span class="p">:</span> <span class="s1">'0.0.0.0'</span>
</span><span class='line'>
</span><span class='line'> <span class="n">options</span><span class="o">[</span><span class="ss">:BindAddress</span><span class="o">]</span> <span class="o">=</span> <span class="n">options</span><span class="o">.</span><span class="n">delete</span><span class="p">(</span><span class="ss">:Host</span><span class="p">)</span> <span class="o">||</span> <span class="n">default_host</span>
</span><span class='line'> <span class="n">options</span><span class="o">[</span><span class="ss">:Port</span><span class="o">]</span> <span class="o">||=</span> <span class="mi">8080</span>
</span><span class='line'> <span class="n">options</span><span class="o">[</span><span class="ss">:OutputBufferSize</span><span class="o">]</span> <span class="o">=</span> <span class="mi">5</span>
</span><span class='line'> <span class="vi">@server</span> <span class="o">=</span> <span class="o">::</span><span class="ss">WEBrick</span><span class="p">:</span><span class="ss">:HTTPServer</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@server</span><span class="o">.</span><span class="n">mount</span> <span class="s2">"/"</span><span class="p">,</span> <span class="ss">Rack</span><span class="p">:</span><span class="ss">:Handler</span><span class="o">::</span><span class="no">WEBrick</span><span class="p">,</span> <span class="n">app</span>
</span><span class='line'> <span class="k">yield</span> <span class="vi">@server</span> <span class="k">if</span> <span class="nb">block_given?</span>
</span><span class='line'> <span class="vi">@server</span><span class="o">.</span><span class="n">start</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>那么就从WEBrick::HTTPServer开始,看看mount和start方法是怎么工作的。</p>
<h1>进入webrick</h1>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">class</span> <span class="nc">HTTPServer</span> <span class="o"><</span> <span class="o">::</span><span class="ss">WEBrick</span><span class="p">:</span><span class="ss">:GenericServer</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>这里有必要说说GenericServer。
其中有两个只读的实例变量:listeners, tokens。
listeners是监听连接的socket数组。
tokens是最大连接数量(并发数量)。</p>
<h3>start方法</h3>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">start</span><span class="p">(</span><span class="o">&</span><span class="n">block</span><span class="p">)</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'> <span class="k">while</span> <span class="vi">@status</span> <span class="o">==</span> <span class="ss">:Running</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'> <span class="k">if</span> <span class="n">svrs</span> <span class="o">=</span> <span class="no">IO</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="vi">@listeners</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="mi">2</span><span class="o">.</span><span class="mi">0</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="n">svrs</span><span class="o">.</span><span class="n">to_s</span><span class="p">)</span>
</span><span class='line'> <span class="n">svrs</span><span class="o">[</span><span class="mi">0</span><span class="o">].</span><span class="n">each</span><span class="p">{</span><span class="o">|</span><span class="n">svr</span><span class="o">|</span>
</span><span class='line'> <span class="vi">@tokens</span><span class="o">.</span><span class="n">pop</span> <span class="c1"># blocks while no token is there.</span>
</span><span class='line'> <span class="k">if</span> <span class="n">sock</span> <span class="o">=</span> <span class="n">accept_client</span><span class="p">(</span><span class="n">svr</span><span class="p">)</span>
</span><span class='line'> <span class="n">sock</span><span class="o">.</span><span class="n">do_not_reverse_lookup</span> <span class="o">=</span> <span class="n">config</span><span class="o">[</span><span class="ss">:DoNotReverseLookup</span><span class="o">]</span>
</span><span class='line'> <span class="n">th</span> <span class="o">=</span> <span class="n">start_thread</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
</span><span class='line'> <span class="n">th</span><span class="o">[</span><span class="ss">:WEBrickThread</span><span class="o">]</span> <span class="o">=</span> <span class="kp">true</span>
</span><span class='line'> <span class="n">thgroup</span><span class="o">.</span><span class="n">add</span><span class="p">(</span><span class="n">th</span><span class="p">)</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="vi">@tokens</span><span class="o">.</span><span class="n">push</span><span class="p">(</span><span class="kp">nil</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>start中,是一个循环。当没有请求的时候,主线程会被select阻塞。有请求的时候,针对每个输入就绪的socket,会通过调用socket的accept方法,来产生一个与客户端通信的新socket,而原来的socket依然在端口上监听。</p>
<p>针对每个与客户端通信的socket,webrick会创建一个线程(相关代码在start_thread中,稍后提及)来处理请求,这里@tokens的作用类似信号量,初始化server的时候,会把@tokens用nil填充满,只有能从@token获取到信号的时候,才可以创建线程,获取不到信号的时候,会阻塞主线程,以此控制并发数量。这里参见之前提到的SizedQueue。</p>
<p>每个请求的具体行为,就要继续查看start_thread了。</p>
<h3>start_thread</h3>
<p>这个方法中是一些异常和logger的处理,主要的一句是</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">start_thread</span><span class="p">(</span><span class="n">sock</span><span class="p">,</span> <span class="o">&</span><span class="n">block</span><span class="p">)</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'> <span class="n">block</span> <span class="p">?</span> <span class="n">block</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span> <span class="p">:</span> <span class="n">run</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
</span><span class='line'> <span class="o">.</span><span class="n">.</span><span class="o">.</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>显而易见,run(sock)就是下个目标。</p>
<h3>run</h3>
<p>这个方法,就要回到::WEBrick::HTTPServer了。</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
<span class='line-number'>48</span>
<span class='line-number'>49</span>
<span class='line-number'>50</span>
<span class='line-number'>51</span>
<span class='line-number'>52</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
</span><span class='line'> <span class="k">while</span> <span class="kp">true</span>
</span><span class='line'> <span class="n">res</span> <span class="o">=</span> <span class="no">HTTPResponse</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@config</span><span class="p">)</span>
</span><span class='line'> <span class="n">req</span> <span class="o">=</span> <span class="no">HTTPRequest</span><span class="o">.</span><span class="n">new</span><span class="p">(</span><span class="vi">@config</span><span class="p">)</span>
</span><span class='line'> <span class="n">server</span> <span class="o">=</span> <span class="nb">self</span>
</span><span class='line'> <span class="k">begin</span>
</span><span class='line'> <span class="n">timeout</span> <span class="o">=</span> <span class="vi">@config</span><span class="o">[</span><span class="ss">:RequestTimeout</span><span class="o">]</span>
</span><span class='line'> <span class="k">while</span> <span class="n">timeout</span> <span class="o">></span> <span class="mi">0</span>
</span><span class='line'> <span class="k">break</span> <span class="k">if</span> <span class="no">IO</span><span class="o">.</span><span class="n">select</span><span class="p">(</span><span class="o">[</span><span class="n">sock</span><span class="o">]</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="kp">nil</span><span class="p">,</span> <span class="mi">0</span><span class="o">.</span><span class="mi">5</span><span class="p">)</span>
</span><span class='line'> <span class="n">timeout</span> <span class="o">=</span> <span class="mi">0</span> <span class="k">if</span> <span class="vi">@status</span> <span class="o">!=</span> <span class="ss">:Running</span>
</span><span class='line'> <span class="n">timeout</span> <span class="o">-=</span> <span class="mi">0</span><span class="o">.</span><span class="mi">5</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">raise</span> <span class="ss">HTTPStatus</span><span class="p">:</span><span class="ss">:EOFError</span> <span class="k">if</span> <span class="n">timeout</span> <span class="o"><=</span> <span class="mi">0</span>
</span><span class='line'> <span class="k">raise</span> <span class="ss">HTTPStatus</span><span class="p">:</span><span class="ss">:EOFError</span> <span class="k">if</span> <span class="n">sock</span><span class="o">.</span><span class="n">eof?</span>
</span><span class='line'> <span class="n">req</span><span class="o">.</span><span class="n">parse</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">request_method</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="n">request_method</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">request_uri</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="n">request_uri</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">request_http_version</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="n">http_version</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">keep_alive</span> <span class="o">=</span> <span class="n">req</span><span class="o">.</span><span class="n">keep_alive?</span>
</span><span class='line'> <span class="n">server</span> <span class="o">=</span> <span class="n">lookup_server</span><span class="p">(</span><span class="n">req</span><span class="p">)</span> <span class="o">||</span> <span class="nb">self</span>
</span><span class='line'> <span class="k">if</span> <span class="n">callback</span> <span class="o">=</span> <span class="n">server</span><span class="o">[</span><span class="ss">:RequestCallback</span><span class="o">]</span>
</span><span class='line'> <span class="n">callback</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
</span><span class='line'> <span class="k">elsif</span> <span class="n">callback</span> <span class="o">=</span> <span class="n">server</span><span class="o">[</span><span class="ss">:RequestHandler</span><span class="o">]</span>
</span><span class='line'> <span class="n">msg</span> <span class="o">=</span> <span class="s2">":RequestHandler is deprecated, please use :RequestCallback"</span>
</span><span class='line'> <span class="vi">@logger</span><span class="o">.</span><span class="n">warn</span><span class="p">(</span><span class="n">msg</span><span class="p">)</span>
</span><span class='line'> <span class="n">callback</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="n">server</span><span class="o">.</span><span class="n">service</span><span class="p">(</span><span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
</span><span class='line'> <span class="k">rescue</span> <span class="ss">HTTPStatus</span><span class="p">:</span><span class="ss">:EOFError</span><span class="p">,</span> <span class="ss">HTTPStatus</span><span class="p">:</span><span class="ss">:RequestTimeout</span> <span class="o">=></span> <span class="n">ex</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">set_error</span><span class="p">(</span><span class="n">ex</span><span class="p">)</span>
</span><span class='line'> <span class="k">rescue</span> <span class="ss">HTTPStatus</span><span class="p">:</span><span class="ss">:Error</span> <span class="o">=></span> <span class="n">ex</span>
</span><span class='line'> <span class="vi">@logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">ex</span><span class="o">.</span><span class="n">message</span><span class="p">)</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">set_error</span><span class="p">(</span><span class="n">ex</span><span class="p">)</span>
</span><span class='line'> <span class="k">rescue</span> <span class="ss">HTTPStatus</span><span class="p">:</span><span class="ss">:Status</span> <span class="o">=></span> <span class="n">ex</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">status</span> <span class="o">=</span> <span class="n">ex</span><span class="o">.</span><span class="n">code</span>
</span><span class='line'> <span class="k">rescue</span> <span class="no">StandardError</span> <span class="o">=></span> <span class="n">ex</span>
</span><span class='line'> <span class="vi">@logger</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="n">ex</span><span class="p">)</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">set_error</span><span class="p">(</span><span class="n">ex</span><span class="p">,</span> <span class="kp">true</span><span class="p">)</span>
</span><span class='line'> <span class="k">ensure</span>
</span><span class='line'> <span class="k">if</span> <span class="n">req</span><span class="o">.</span><span class="n">request_line</span>
</span><span class='line'> <span class="k">if</span> <span class="n">req</span><span class="o">.</span><span class="n">keep_alive?</span> <span class="o">&&</span> <span class="n">res</span><span class="o">.</span><span class="n">keep_alive?</span>
</span><span class='line'> <span class="n">req</span><span class="o">.</span><span class="n">fixup</span><span class="p">()</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="n">res</span><span class="o">.</span><span class="n">send_response</span><span class="p">(</span><span class="n">sock</span><span class="p">)</span>
</span><span class='line'> <span class="n">server</span><span class="o">.</span><span class="n">access_log</span><span class="p">(</span><span class="vi">@config</span><span class="p">,</span> <span class="n">req</span><span class="p">,</span> <span class="n">res</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">break</span> <span class="k">if</span> <span class="vi">@http_version</span> <span class="o"><</span> <span class="s2">"1.1"</span>
</span><span class='line'> <span class="k">break</span> <span class="k">unless</span> <span class="n">req</span><span class="o">.</span><span class="n">keep_alive?</span>
</span><span class='line'> <span class="k">break</span> <span class="k">unless</span> <span class="n">res</span><span class="o">.</span><span class="n">keep_alive?</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<h3>req.parse</h3>
<p>从socket读取请求报文,构造request实例。</p>
<figure class='code'><figcaption><span></span></figcaption><div class="highlight"><table><tr><td class="gutter"><pre class="line-numbers"><span class='line-number'>1</span>
<span class='line-number'>2</span>
<span class='line-number'>3</span>
<span class='line-number'>4</span>
<span class='line-number'>5</span>
<span class='line-number'>6</span>
<span class='line-number'>7</span>
<span class='line-number'>8</span>
<span class='line-number'>9</span>
<span class='line-number'>10</span>
<span class='line-number'>11</span>
<span class='line-number'>12</span>
<span class='line-number'>13</span>
<span class='line-number'>14</span>
<span class='line-number'>15</span>
<span class='line-number'>16</span>
<span class='line-number'>17</span>
<span class='line-number'>18</span>
<span class='line-number'>19</span>
<span class='line-number'>20</span>
<span class='line-number'>21</span>
<span class='line-number'>22</span>
<span class='line-number'>23</span>
<span class='line-number'>24</span>
<span class='line-number'>25</span>
<span class='line-number'>26</span>
<span class='line-number'>27</span>
<span class='line-number'>28</span>
<span class='line-number'>29</span>
<span class='line-number'>30</span>
<span class='line-number'>31</span>
<span class='line-number'>32</span>
<span class='line-number'>33</span>
<span class='line-number'>34</span>
<span class='line-number'>35</span>
<span class='line-number'>36</span>
<span class='line-number'>37</span>
<span class='line-number'>38</span>
<span class='line-number'>39</span>
<span class='line-number'>40</span>
<span class='line-number'>41</span>
<span class='line-number'>42</span>
<span class='line-number'>43</span>
<span class='line-number'>44</span>
<span class='line-number'>45</span>
<span class='line-number'>46</span>
<span class='line-number'>47</span>
</pre></td><td class='code'><pre><code class='ruby'><span class='line'><span class="k">def</span> <span class="nf">parse</span><span class="p">(</span><span class="n">socket</span><span class="o">=</span><span class="kp">nil</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@socket</span> <span class="o">=</span> <span class="n">socket</span>
</span><span class='line'> <span class="k">begin</span>
</span><span class='line'> <span class="vi">@peeraddr</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">respond_to?</span><span class="p">(</span><span class="ss">:peeraddr</span><span class="p">)</span> <span class="p">?</span> <span class="n">socket</span><span class="o">.</span><span class="n">peeraddr</span> <span class="p">:</span> <span class="o">[]</span>
</span><span class='line'> <span class="vi">@addr</span> <span class="o">=</span> <span class="n">socket</span><span class="o">.</span><span class="n">respond_to?</span><span class="p">(</span><span class="ss">:addr</span><span class="p">)</span> <span class="p">?</span> <span class="n">socket</span><span class="o">.</span><span class="n">addr</span> <span class="p">:</span> <span class="o">[]</span>
</span><span class='line'> <span class="k">rescue</span> <span class="ss">Errno</span><span class="p">:</span><span class="ss">:ENOTCONN</span>
</span><span class='line'> <span class="k">raise</span> <span class="ss">HTTPStatus</span><span class="p">:</span><span class="ss">:EOFError</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="n">read_request_line</span><span class="p">(</span><span class="n">socket</span><span class="p">)</span>
</span><span class='line'> <span class="k">if</span> <span class="vi">@http_version</span><span class="o">.</span><span class="n">major</span> <span class="o">></span> <span class="mi">0</span>
</span><span class='line'> <span class="n">read_header</span><span class="p">(</span><span class="n">socket</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@header</span><span class="o">[</span><span class="s1">'cookie'</span><span class="o">].</span><span class="n">each</span><span class="p">{</span><span class="o">|</span><span class="n">cookie</span><span class="o">|</span>
</span><span class='line'> <span class="vi">@cookies</span> <span class="o">+=</span> <span class="ss">Cookie</span><span class="p">:</span><span class="ss">:parse</span><span class="p">(</span><span class="n">cookie</span><span class="p">)</span>
</span><span class='line'> <span class="p">}</span>
</span><span class='line'> <span class="vi">@accept</span> <span class="o">=</span> <span class="no">HTTPUtils</span><span class="o">.</span><span class="n">parse_qvalues</span><span class="p">(</span><span class="nb">self</span><span class="o">[</span><span class="s1">'accept'</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@accept_charset</span> <span class="o">=</span> <span class="no">HTTPUtils</span><span class="o">.</span><span class="n">parse_qvalues</span><span class="p">(</span><span class="nb">self</span><span class="o">[</span><span class="s1">'accept-charset'</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@accept_encoding</span> <span class="o">=</span> <span class="no">HTTPUtils</span><span class="o">.</span><span class="n">parse_qvalues</span><span class="p">(</span><span class="nb">self</span><span class="o">[</span><span class="s1">'accept-encoding'</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@accept_language</span> <span class="o">=</span> <span class="no">HTTPUtils</span><span class="o">.</span><span class="n">parse_qvalues</span><span class="p">(</span><span class="nb">self</span><span class="o">[</span><span class="s1">'accept-language'</span><span class="o">]</span><span class="p">)</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'> <span class="k">return</span> <span class="k">if</span> <span class="vi">@request_method</span> <span class="o">==</span> <span class="s2">"CONNECT"</span>
</span><span class='line'> <span class="k">return</span> <span class="k">if</span> <span class="vi">@unparsed_uri</span> <span class="o">==</span> <span class="s2">"*"</span>
</span><span class='line'>
</span><span class='line'> <span class="k">begin</span>
</span><span class='line'> <span class="n">setup_forwarded_info</span>
</span><span class='line'> <span class="vi">@request_uri</span> <span class="o">=</span> <span class="n">parse_uri</span><span class="p">(</span><span class="vi">@unparsed_uri</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@path</span> <span class="o">=</span> <span class="ss">HTTPUtils</span><span class="p">:</span><span class="ss">:unescape</span><span class="p">(</span><span class="vi">@request_uri</span><span class="o">.</span><span class="n">path</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@path</span> <span class="o">=</span> <span class="ss">HTTPUtils</span><span class="p">:</span><span class="ss">:normalize_path</span><span class="p">(</span><span class="vi">@path</span><span class="p">)</span>
</span><span class='line'> <span class="vi">@host</span> <span class="o">=</span> <span class="vi">@request_uri</span><span class="o">.</span><span class="n">host</span>
</span><span class='line'> <span class="vi">@port</span> <span class="o">=</span> <span class="vi">@request_uri</span><span class="o">.</span><span class="n">port</span>
</span><span class='line'> <span class="vi">@query_string</span> <span class="o">=</span> <span class="vi">@request_uri</span><span class="o">.</span><span class="n">query</span>
</span><span class='line'> <span class="vi">@script_name</span> <span class="o">=</span> <span class="s2">""</span>
</span><span class='line'> <span class="vi">@path_info</span> <span class="o">=</span> <span class="vi">@path</span><span class="o">.</span><span class="n">dup</span>
</span><span class='line'> <span class="k">rescue</span>
</span><span class='line'> <span class="k">raise</span> <span class="ss">HTTPStatus</span><span class="p">:</span><span class="ss">:BadRequest</span><span class="p">,</span> <span class="s2">"bad URI `</span><span class="si">#{</span><span class="vi">@unparsed_uri</span><span class="si">}</span><span class="s2">'."</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'>
</span><span class='line'> <span class="k">if</span> <span class="sr">/close/io</span> <span class="o">=~</span> <span class="nb">self</span><span class="o">[</span><span class="s2">"connection"</span><span class="o">]</span>
</span><span class='line'> <span class="vi">@keep_alive</span> <span class="o">=</span> <span class="kp">false</span>
</span><span class='line'> <span class="k">elsif</span> <span class="sr">/keep-alive/io</span> <span class="o">=~</span> <span class="nb">self</span><span class="o">[</span><span class="s2">"connection"</span><span class="o">]</span>
</span><span class='line'> <span class="vi">@keep_alive</span> <span class="o">=</span> <span class="kp">true</span>
</span><span class='line'> <span class="k">elsif</span> <span class="vi">@http_version</span> <span class="o"><</span> <span class="s2">"1.1"</span>
</span><span class='line'> <span class="vi">@keep_alive</span> <span class="o">=</span> <span class="kp">false</span>
</span><span class='line'> <span class="k">else</span>
</span><span class='line'> <span class="vi">@keep_alive</span> <span class="o">=</span> <span class="kp">true</span>
</span><span class='line'> <span class="k">end</span>
</span><span class='line'><span class="k">end</span>
</span></code></pre></td></tr></table></div></figure>
<p>先是解析请求行,再是请求报文头部解析,最后确定keep_alive</p>
<p>回到run。</p>
<p>一般的使用情况下server都是self,lookup_server与virtual_hosts有关。server.service就是self.service,其中,找到了真正的servlet的实例,并调用实例的service方法。其中可以看看mount方法的作用:可以把不同的servlet mount不同的url上,形成一个路由表。</p>
<p>rack的webrick handler就是一个webrick servlet,并且复写了service这个方法。server.service(req, res)调用完毕,那么response的各个属性也就填好了,接着<code>res.send_response(sock)</code>会通过socket来发送数据。</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[一次聊天服务器性能调优经历分享]]></title>
<link href="http://creatingev.github.io/blog/2014/01/08/chat-server-performance-tune/"/>
<updated>2014-01-08T08:48:28+08:00</updated>
<id>http://creatingev.github.io/blog/2014/01/08/chat-server-performance-tune</id>
<content type="html"><![CDATA[<p>导读:<br/>
这是我的一次性能调优经历的分享,我的本意不是分享我调优所获得的知识与经验,而是希望可以启发大家的思考。如天放所说,其实最有效完成一个目标的方式是用二分法,逐步找到问题的解决办法。但二分法的本质是趋利避害,是以目标为导向的方法,追求最短时间解决一个问题,追求最易解决问题的办法。二分法可能是高效地解决问题的好办法,但却不是学习的好方法。</p>
<p>“名人哲言”里有一句话,“上帝若為你關了一扇門,必然為你開另一扇門”,在这里,恰恰相反,“当你开了一扇门,你必然会关上另外一扇门”。当你用二分法解决了你的问题,并为此窃喜之时,或许被你关上的无数扇门了有你追求了许久的宝藏,这些宝藏一次次与你擦肩而过。从长远的角度来讲,二分法不见得是最高效的办法。</p>
<p>带着问题去学习,才是一个最高效的学习方式,在我们去完成我们的目标的时候,我们会碰到各种各样的问题,正是这些问题的存在,才让我们逐步减少因我们片段学习(我们的许多知识是通过google得到的)而产生的割裂性,逐渐完整化,系统化。而二分法在许多时候,会让我们规避掉这些问题,导致我们错失最好的学习机会。</p>
<p>在我的这次经验中,我获得了一些看起来很简单,但是却让我受益无穷的经验和知识宝藏,有了这些知识的夯实,我才能慢慢往更深的地方走去。或许可以这么说,二分法是一个解决问题的好办法,但不是一个提高知识深度的好办法。而提高你的知识深度,有时候,需要你违背二分法的原则,脑子缺根筋,在一条未知的路上反复探索,才能到达更深的地步。</p>
<p>理是这么个理,你需要有足够的智慧去区分什么时候需要用二分法,什么时候需要钻牛角尖。其实最简单的办法是看时间的要求,在时间紧张的时候,我们应该追求效率,在时间充裕的时候,我们应该追求深度,对问题穷追不舍。我觉得每个人都应该在快速的节奏下,停下来想一想,去深究一些问题,张弛有度才是一个健康的方式。这也是为什么我希望我们的开发节奏是一大一小穿插的方式进行的原因。(但看起来,大部分人都误用了小版本的用途,小版本最主要的目的是希望你能深究一些你碰到的难题,比如重构,比如UI效果,而现在大家却只用小版本来解决小bug…)</p>
<p>第二件,我想通过这次经历分享的是,面对未知原因的问题的时候,其实每个人都可以解决。用最笨的办法,用最小时候学过的做实验的办法。我们小时候做过许多化学实验,物理实验,老师通常会选一组参照物,最终通过与参照物对比的方式来得出我们的结论。所以我们碰到未知问题的时候,也同样的可以用这样的办法解决,但请注意最重要的一点,要保证参照物与实验对象只有唯一一点不同,这样结论才是正确的,否则实验没有任何意义。所以大胆假设,小心求证才显得如此重要。</p>
<p>有参照物的问题,每个人都有办法去解决,每个人都不要错过这样一个完美的学习的机会。</p>
<p>这次调优经历不见得是最高效,最好的方式,结果也不见得是最好的结果,但我想,希望我的这次抛砖引玉,可以给大家带来更多的思考。</p>
<hr />
<p>ppt内容预览下载地址(可以用上一页,下一页翻页,这样就像ppt了):<a href="http://pan.baidu.com/s/1sjybu8X">http://pan.baidu.com/s/1sjybu8X</a></p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Splitting a Fat Model Into Multiple Files]]></title>
<link href="http://creatingev.github.io/blog/2013/12/04/splitting-a-fat-model-into-multiple-files/"/>
<updated>2013-12-04T18:07:10+08:00</updated>
<id>http://creatingev.github.io/blog/2013/12/04/splitting-a-fat-model-into-multiple-files</id>
<content type="html"><![CDATA[<h2>起因</h2>
<p>Rails的应用内,总有一些超级复杂的model,比如User。而正因是<strong>胖model,瘦controller</strong>这样的指导思想,会导致一些model臃肿不堪,有些model甚至会超过1000行,而一旦超过1000行,一个类的代码就变得难以维护了。所以一段时间内,我们为了不让我们的model太臃肿,我们只能不往User里面写代码,而把一些代码写在其他的model里面。比如写成如下的方式</p>
<pre><code>#exam.rb
class Exam < ActiveRecord::Base
def add_user(user)
end
end
</code></pre>
<p>但这样的方式<code>Exam.add_user(user)</code>明显没有<code>user.join_exam(exam)</code>直观。</p>
<pre><code>#user.rb
class User < ActiveRecord::Base
def join_exam(exam)
end
end
</code></pre>
<p>所以为了兼顾直观与保持model可维护性更高,我查找了一些资料,尝试为我们的model瘦身。</p>
<h2>解决思路</h2>
<p>一个广为流传的办法是<a href="https://gist.github.com/dhh/1014971">Use concerns to keep your models manageable</a>,这是dhh(Creator of Ruby on Rails)大神推荐的方式,已被列入Rails4的规范之中了(<a href="http://ruby-china.org/topics/7709">Rails4重大设计决策:“胖”Model用ActiveSupport::Concern瘦身</a>)。</p>
<p>但使用concern的根本目的不是为了解决单个model的肥胖问题,而是为了让一些model通用的代码片段存在于一个合适的位置,比如commentable,这样但凡有用到comment的model,只要<code>include commentable</code>就可以实现评论相关的功能,这样的实现方式既简单又直观。</p>
<p>如果为model瘦身,主要的问题是,如何分离你的业务逻辑,因为单纯的将代码发在几个小文件中是没有什么意义的(为什么没有意义?因为会增加你查找的难度和理解的难度),这也是为什么<a href="http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/">7 Patterns to Refactor Fat ActiveRecord Models</a>说</p>
<pre><code>“Any application with an app/concerns directory is concerning.”
</code></pre>
<p>的一个重要原因。</p>
<p>所以综合以上思路,最终实践得出了三个可以简化User model的办法</p>
<ul>
<li>为model抽象一些功能性concern,比如Authenticatable, Genderable。</li>
<li>为model分离一些业务相关模块。比如user_post, 比如 user_event</li>
<li>将特殊的功能模块抽象成class</li>
</ul>
<h2>实践</h2>
<p>以下实践均以User model为例</p>
<h3>为model抽象一些功能性concern</h3>
<p>这样做符合concern本身的意图,比如将用户验证的相关操作和相关scope放在Authenticatable的module,这样User就拥有了可拔插的能力,如果想去掉相关的功能,只需要取消include就可以了。</p>
<p>所以,这部分的代码类似于</p>
<pre><code>#app/models/concerns/authenticatable.rb
# -*- encoding : utf-8 -*-
module Authenticatable
extend ActiveSupport::Concern
included do
def self.basic_auth(account, password)
end
end
def has_password?
end
end
</code></pre>
<h3>为model分离一些业务相关模块</h3>
<p>这样做是不太符合concern本身的意图的,但借用concern来表达我们的业务逻辑,也没有什么问题。但这样做最大的问题是,这部分的concern不应该和传统的concern混在一起,这样不同model的业务逻辑容易混乱(至少不好查找)。</p>
<p>所以,我们将这部分代码放在了<code>app/models/concerns/user_concern/</code>中,代码类似如下</p>
<pre><code>#app/models/concerns/user_concern/post.rb
# -*- encoding : utf-8 -*-
module UserConcern
module Post
extend ActiveSupport::Concern
included do
has_many :posts, :dependent => :destroy
has_many :other_posts, :dependent => :destroy
end
end
end
</code></pre>
<h3>将特殊的功能模块抽象成class</h3>
<p>这种办法最受<a href="http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/">7 Patterns to Refactor Fat ActiveRecord Models</a>推崇,所以,可以借鉴一些这边文章提到的一些方法来抽象我们的代码。这部分代码类似于</p>
<pre><code>#app/models/lib/edit_limit.rb
# -*- encoding : utf-8 -*-
class EditLimit
NO_MODIFY_LIMIT_USERS_KEY = "no_modify_limit_users"
MODIFY_LIMIT = 5
MODIFY_LIMIT_KEY = "editable_times_%d"
def initialize(user)
@user = user
end
def self.no_modify_limit_users
Rails.cache.fetch NO_MODIFY_LIMIT_USERS_KEY do
Set.new
end
end
def self.add_no_modify_limit_user(user)
no_limit_user_ids = no_modify_limit_users
no_limit_user_ids << user.id
Rails.cache.write NO_MODIFY_LIMIT_USERS_KEY, no_limit_user_ids
no_limit_user_ids
end
end
</code></pre>
<h3></h3>
<p>最终,我们在user.rb的引用如下所示</p>
<pre><code>#app/models/user.rb
class User < ActiveRecord::Base
include Authenticatable
include UserConcern::Post
end
</code></pre>
<h2>总结</h2>
<p>因为Rails本身的设计,对于一些不太复杂的逻辑与应用,实在无需煞费苦心去寻求瘦身与简化。因为符合Rails本身的设计思想在很大程度上就已经很好的分离了model,view,controller(MVC)三者的职责。而一些复杂的应用,在不考虑更好的可读性的前提下(比如将许多逻辑放置在关联表中),也不会形成太过肥胖的model。所以,只有一些人像我这样对可读性有些洁癖,又想让model保持简单的人,才需要类似的解决办法。</p>
<h2>参考资料</h2>
<ul>
<li><a href="https://gist.github.com/dhh/1014971">Use concerns to keep your models manageable</a></li>
<li><a href="http://blog.codeclimate.com/blog/2012/10/17/7-ways-to-decompose-fat-activerecord-models/">7 Patterns to Refactor Fat ActiveRecord Models</a></li>
<li><a href="https://37signals.com/svn/posts/3372-put-chubby-models-on-a-diet-with-concerns">Put chubby models on a diet with concerns</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[一定会发生和一定不会发生的事情]]></title>
<link href="http://creatingev.github.io/blog/2013/12/03/something-about-probability/"/>
<updated>2013-12-03T06:25:41+08:00</updated>
<id>http://creatingev.github.io/blog/2013/12/03/something-about-probability</id>
<content type="html"><![CDATA[<p>谈起这个话题,原因是我的一次愚蠢的尝试。我曾经在一个游戏中用虚拟积分玩过这样的游戏,我先用1个积分去投注,如果输了,我就翻倍去投注,直到我输光为止。而我不相信我能连输十盘,我觉得那是一个不可能发生的事情。结果很明显,我为了赚一个积分,把我的所有积分都输光了。所以从这点出发,我觉得有必要去正视什么是一定会发生的事情,什么是一定不会发生的事情,两者的边界是什么?</p>
<h2>一定会发生的事情</h2>
<h3>赌博</h3>
<p>以我上述的例子为准,假设你的人品爆发,碰到赌场了绝对公平的游戏,你赢的概率有50%。所以我们可以计算一下你连输10(或11次,下方是11次的概率)盘,输掉内裤的概率有多大。</p>
<pre><code>连输11次的概率=m¹º=0.0009765625 其中m=0.5
</code></pre>
<p>所以,很明显你连输11盘的概率很低,换言之,你赢的概率达到了99.90%,这个概率达到了千足金的含金量。可问题是,这够稳固吗?这就意味着,你玩1000次,你就要输掉一次,只为了赚1块钱。</p>
<p>ok,你可以说假设你每天玩一次,1000天才会输掉一次,就是说快3年你才输掉一次。这看起来还挺好的。<code>常胜将军</code>。但问题关键是,这是赌博,赌博最重要的一点是趋利,是贪婪,没有人会满足一天只赚一块钱,说不定你一天就会玩上100盘,不到十天,你就输光了你的所有资本。</p>
<p>我称上述的例子为一定会发生的事情,哪怕它的概率达到了99.9%。</p>
<h2>一定不会发生的事情</h2>
<h3>飞机失事</h3>
<p>众所周知,飞机失事的概率是很低的,但到底是一个什么量级的数据呢?</p>
<p>据<a href="http://planecrashinfo.com/cause.htm">Accident statistics</a>的统计,平均340万次飞行才会有一次至少一人死亡的记录,所以全身而退的概率就等于</p>
<pre><code>1-1/3400000 = 0.99999970588
</code></pre>
<p>这个比例就相当于,如果象梁朝伟一样,每天飞到巴黎去喂个鸽子,第二天飞回来(每天一次飞机)。那么9315年才能出现一次(至少一个人死亡)的飞机失事。</p>
<p>所以这个比例在我们看来是几乎不会出现的概率,我们暂时可以称之为一定不会发生的事情。</p>
<h3>UUID(Universally Unique Identifier)</h3>
<p>UUID是计算机上普遍使用的用于唯一标识的标识符。它一般是根据mac地址+时间戳+随机数生成的。</p>
<pre><code>UUID的标准型式包含32个16进位数字,以连字号分为五段,形式为8-4-4-4-12的32个字符。示例:
550e8400-e29b-41d4-a716-446655440000
</code></pre>
<p>所以假设UUID是全随机的,那么它的概率是</p>
<pre><code>16的32次方 = 3.4 x 10的38次方
</code></pre>
<p>所以,也就是说随机两次,重复一次的概率=1/ 3.4*10的38次方</p>
<p>那随机UUID的重复机率是多少呢?</p>
<pre><code>随机产生的UUID(例如说由java.util.UUID类型产生的)的128个比特中,有122个比特是随机产生,4个比特在此版本('Randomly generated UUID')被使用,还有2个在其变体('Leach-Salz')中被使用。利用生日悖论,可计算出两笔UUID拥有相同值的机率约为
p(n)\approx 1-e^{-n^2/{2 \cdot x}}
以下是以x=2122计算出n笔UUID后产生碰撞的机率:
n 机率
68,719,476,736 = 2的36次方 0.0000000000000004 (4 x 10-16)
2,199,023,255,552 = 2的41方 0.0000000000004 (4 x 10-13)
70,368,744,177,664 = 2的46方 0.0000000004 (4 x 10-10)
与被陨石击中的机率比较的话,已知一个人每年被陨石击中的机率估计为170亿分之1[1],也就是说机率大约是0.00000000006 (6 x 10-11),等同于在一年内置立数十兆笔UUID并发生一次重复。换句话说,每秒产生10亿笔UUID,100年后只产生一次重复的机率是50%。如果地球上每个人都各有6亿笔UUID,发生一次重复的机率是50%。
产生重复UUID并造成错误的情况非常低,是故大可不必考虑此问题。
机率也与乱数产生器的质量有关。若要避免重复机率提高,必须要使用奠基于密码学上的假乱数产生器来生成值才行。
</code></pre>
<p>所以,UUID的重复可以认为是一定不可能发生的事情。而这个概率相比飞机失事的概率来说,对我们来说,那真的是非常非常放心了。如果飞机失事的概率达到UUID重复的概率,那就没有空难了。</p>
<h2>两者的边界</h2>
<p>当我们去评估哪一些属于一定会发生,哪些是一定不会发生的时候,有两个指标。一个是单次发生的概率,第二个是你重复的次数。而我们去评估的时候,通常会以相对夸张的次数来评估最终发生的概率。</p>
<p>以飞机失事的概率来计算,假设一个人的寿命是90年,每天坐一班飞机。那么他在有生之年失事的概率<1%。虽然没有绝对安全,但相对更为复杂的生存环境,我觉得这已经是一个完美的概率了。</p>
<p>所以我觉得,飞机失事的概率为分界(1%的最终概率),远大于最终死亡概率的,那么它就可以认为是一定会发生的事情,而远小于最终死亡概率的,那么可以列为安全概率。而在这概率附近的,看你个人自己的看法啦。</p>
<h2>参考资料</h2>
<ul>
<li><a href="http://www.360doc.com/content/11/1126/15/5575132_167527846.shtml">大型客机空难事故率排名</a></li>
<li><a href="http://planecrashinfo.com/cause.htm">Accident statistics</a></li>
<li><a href="http://zh.wikipedia.org/w/index.php?title=%E7%94%9F%E6%97%A5%E6%94%BB%E5%87%BB&variant=zh-cn">生日问题</a></li>
<li><a href="http://zh.wikipedia.org/w/index.php?title=UUID&variant=zh-cn">UUID</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[我们真正关心的事情]]></title>
<link href="http://creatingev.github.io/blog/2013/11/30/what-we-really-care/"/>
<updated>2013-11-30T09:13:54+08:00</updated>
<id>http://creatingev.github.io/blog/2013/11/30/what-we-really-care</id>
<content type="html"><![CDATA[<p>如果你是位新员工,你可能会有一些困惑,我们没有代码规范,却要求你代码应该这么写,而不应该那么写,相同的,我们会建议你有些事情应该这样做,而不是那么做。你不知道到底哪些事情才是最重要的,在不知道优先级的情况下,你可能会犯一些错误,你会让你感到很沮丧。所以,从一个更严谨的角度,我应该把我们真正在乎的事情全都告诉你。
我们真正在乎的事情是:</p>
<ul>
<li>工作态度</li>
<li>效率</li>
<li>创造性</li>
</ul>
<h2>工作态度</h2>
<h3>认真严谨的工作态度</h3>
<p>这件事情,我在之前提过,你可以参考<a href="blog/2013/11/30/an-advise-to-the-new-staff">an advise to the new staff</a>,这是最最重要的事情,这是我们接下来要说的所有事情的前提。</p>
<h3>我们没有程序员,只有工程师</h3>
<p>希望你可以理解这句听上去有点绕口的话。程序员和工程师,在我的理解,两者最大的区别,前者只工作在代码开发阶段,而后者参与一件事情的全部(请以广义的工程师来理解,非片面的IT工程师)。而这点区别决定了,在这里,你不是对你的leader负责,而是对整个产品负责。所以需要要求你:</p>
<ul>
<li>希望你以用户的眼光来看待问题。不管是API接口还是App开发,请以用户的视角来看待问题。不要犯类似于给用户的接口却不关心排序这么低级的错误。</li>
<li>在你的角度,尽你所能推进事情的进展。请记住你不是一个程序员,你可以推动相关人员在这件事情上的进度,(比如推动设计师完成急需的东西)。请不要置身事外,等待事情的进展。</li>
<li>写代码之前先想清楚,先写spec梳理整个功能的开发以及后续。</li>
</ul>
<p>在职责之外,也有属于你的权利</p>
<ul>
<li>你可以强烈坚持你的意见。(但在申诉无效之后,请服从团队的决定)</li>
<li>关于对于产品的建议,你的建议会比其他人的更受重视。</li>
</ul>
<h2>效率</h2>
<p>效率是团队竞争力的根基。围绕效率,有一系列我们推崇的工作方式</p>
<h3>效率、专注——番茄工作法</h3>
<p>专注能力是一种宝贵的资源,你只有在专注的时候,你才能用一些方法来提高你的效率。<a href="http://wiki.mbalib.com/wiki/%E7%95%AA%E8%8C%84%E5%B7%A5%E4%BD%9C%E6%B3%95">番茄工作法</a>(<a href="http://www.focusboosterapp.com/">简易工具下载</a>)可以帮助你集中注意力,提高效率。这是我们实践过的极为有效的一种办法,使用番茄工作法的还有一个好处是可以尽快帮你从糟糕的状态里走出来。</p>
<h3>异步工作方式</h3>
<p>异步工作方式保障了你好不容易积累起来的注意力不会被轻易打断。请参考<a href="blog/2013/11/30/be-asynchronous/">be asynchronous</a>。</p>
<h3>不要过度设计,用迭代的方法去做事情</h3>
<p>实现最小可用原型,然后用迭代的办法去完善它。这是所有敏捷开发最重要的一点。而这一点,也体现在我们工作中的方方面面。它帮助我们训练自己如何在缺乏资源的情况下,完成一件最小可用的模型,同时,也帮我们学会去抽象和简化一件事情,而<strong>抽象</strong>是程序设计最重要的能力之一。</p>
<h3>TDD(测试驱动开发)</h3>
<p>没错,把TDD放在这里是因为它能帮我们提高效率。TDD可以帮我们</p>
<ul>
<li>检查代码逻辑,很难被测试的代码就是一个强烈的可以被重构的信号。</li>
<li>减少人工检查的时间。</li>
<li>提高交付的正确率,节约大家的时间。</li>
</ul>
<h3>重构</h3>
<p>重构最重要的一点是可以嗅得到<em>坏代码</em>的味道,而坏代码是所有bug的温床,是阅读和理解代码的拦路虎。适当的及时的重构一些不合理的代码可以帮助<strong>减少bug</strong>,节约其他人理解代码的时间。</p>
<p>而之所以需要频繁的重构,是因为我们采用迭代的方法来编写我们的代码,而在迭代初期,适当的简化和抽象逻辑是为了更快地完成我们的最小可用模型。但我们在修改和完善我们的代码的时候,我们必须要及时的把一些不再合理的代码改写掉,使之更健壮。</p>
<h2>创造性</h2>
<p>创造性是一个老生常谈的话题,也是一个可遇而不可求的东西。这看起来是一个非常虚和无法落实的话题。每个个体的创造性是一个概率问题,但一个团队的创造性却是一个竞争力问题。而这一点是发展过程中,不可避免的。</p>
<p>所以,为了提高自己和团队的创造性,希望大家可以找到hacker的感觉。hacker不是指入侵和破坏,而是一种无边界的思维方式。希望大家有这方面的体验和训练。</p>
<h2></h2>
<p>其实,这篇东西里讲的东西非常之多,非常之大,每个单独的东西拿出来都是可以单独出书的。之所以简要罗列于此,是希望大家可以明白和认同什么才是我们真正关注的东西。</p>
<h3>参考资料</h3>
<ul>
<li><a href="http://book.douban.com/subject/1229923/">重构(办公室有书籍)</a></li>
<li><a href="http://wiki.mbalib.com/wiki/%E7%95%AA%E8%8C%84%E5%B7%A5%E4%BD%9C%E6%B3%95">番茄工作法</a></li>
<li><a href="blog/2013/11/30/an-advise-to-the-new-staff">an advise to the new staff</a></li>
<li><a href="blog/2013/11/30/be-asynchronous/">be asynchronous</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[BE ASYNCHRONOUS]]></title>
<link href="http://creatingev.github.io/blog/2013/11/30/be-asynchronous/"/>
<updated>2013-11-30T07:53:57+08:00</updated>
<id>http://creatingev.github.io/blog/2013/11/30/be-asynchronous</id>
<content type="html"><![CDATA[<p>上次的团队分享中,跟大家分享了github的异步的工作方式。把大家的建议总结一下,并发起一个倡议。希望大家可以遵守并形成我们自己的异步的工作方式。</p>
<p>异步的工作方式的优点不言而喻,缩短等待(block)的时间,不会打扰其他人的工作。而这两点归根结底,会影响团队的工作效率,而效率,是一个团队,尤其是创业团队的命根子。</p>
<p>所以要想做到异步的工作方式,我们需要做到:</p>
<ol>
<li>保障自己的成果输出质量。希望每个人都可以严格要求自己,对自己的输出成果负责。这其中包括
<ul>
<li>服务端提供给API接口的正确性保障</li>
<li>App客户端提供给大家测试版本的基本正确性(减少明显错误的地方)</li>
<li>设计输出给开发的切图的完整性与正确性</li>
</ul>
</li>
<li><p>规范交付成果</p>
<p> 以API接口为例,在API接口可测试的同时,需要告诉App开发工程师,接口的url以及接口参数和调用说明。如果非绝对必要,请以异步的方式交付这些东西,比如email或者QQ的方式告诉相关的人员。</p></li>
<li><p>建立安静的工作氛围(强制大家以异步的方式来沟通)</p>
<p> 因为我们的工作环境是一个大开间,这样设计的原因是为了体现大家的平等,没有人应该有办公室,所有人包括天放在内都是平等的(虽然以后可能会改变,但改变不是为了体现特权,而是特殊原因,比如不应该被频繁打扰)。但大开间对工作效率是有害的(我在hackernews上见过类似的控诉),因为会有一些有意无意的打断和干扰,我相信这也是为什么天放设立效率室的原因。所以,为了减少大开间带来的弊端,我希望可以做到:</p>
<ul>
<li>安静的沟通方式,QQ为主,小声的讨论。如需要讨论激烈的话题,请到会议室讨论。(抱歉,在这一点上我做得非常不好,请大家监督,下不为例)</li>
<li><strong>不打扰带耳机的同事</strong>。如果你不希望被打扰,请带上耳机。同样的,你也不应该打扰带耳机的同事,哪怕他就坐在你旁边(你可以用QQ告知)。当然,真正紧急的事情除外。(但你要有能力区分哪些是真正紧急的事情)</li>
<li>有些需要面对面沟通的事情,尽量放在scrum会议以及中午和晚上吃饭的时间附近。</li>
</ul>
</li>
</ol>
<p>差不多是以上几点。此外有一些技巧可以减少你被阻塞(block)的机会,以及在被阻塞(block)住之后,可以继续进行下去的办法。</p>
<ul>
<li><p>花一些时间在跟你的工作有交集的地方,比如App开发组,需要花一些时间在服务端的开发上,和设计的工作方式上,这样可以减少你被block的机会,以API接口为例,如果你真不清楚某个接口的参数,你可以直接去后台代码中查看,这样可以节省很多时间。</p></li>
<li><p>培养处理block的能力。还是以App开发组为例,要有能力在没有接口和切图的前提下,去完成App的逻辑。这样在碰到block的地方,可以轻易跳过。</p></li>
<li><p>两件事情并行的能力。虽然原则上你要一件件的事情去做,优质地完成一件事情之后,再去做另外一件事情。这样可以减少事情烂尾的风险。但真被block住的事情,希望你能有快速切换到另外一件事情的能力。这就要求你有良好的开发习惯。</p>
<ul>
<li>合适的commit粒度</li>
<li>每件事情一个branch的开发原则</li>
<li>了解和理解团队和你的优先级</li>
</ul>
</li>
</ul>
<p>希望和大家一起享受异步的工作方式。</p>
<h3>参考资料</h3>
<ul>
<li><a href="http://zachholman.com/talk/how-github-no-longer-works/">HOW GITHUB (NO LONGER) WORKS</a></li>
<li><a href="http://zachholman.com/posts/how-github-works-asynchronous/">HOW GITHUB WORKS: BE ASYNCHRONOUS</a></li>
</ul>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[An Advise to the New Staff]]></title>
<link href="http://creatingev.github.io/blog/2013/11/30/an-advise-to-the-new-staff/"/>
<updated>2013-11-30T06:43:21+08:00</updated>
<id>http://creatingev.github.io/blog/2013/11/30/an-advise-to-the-new-staff</id>
<content type="html"><![CDATA[<p>hi,新来的同学,欢迎加入我们的团队。</p>
<p>我们是一个甚少约束的公司,你可以自由选择自己的工作时间,自由选择自己的工作方式,在保证效率的前提下,你几乎可做任何尝试,比如站着办公,比如去不受打扰的房间一个人待着。(虽然除了我和天放,几乎没有人这样做过,但实际上我希望大家这么做,希望每个人都可以找到属于的自己的高效率的钥匙),甚至可以在家办公(你可以尝试,我尝试过,但效果不佳)。</p>
<p>我们在编程风格上和团队交流上都没有强制的建议。(比如所有成果必须文档化,在做之前必须写设计文档之类的)。但我们建议你可以遵从语言本身的编码规范,这样可以减少犯错的机会和降低交流的成本。</p>
<p>在团队的建设过程中,我们也逐渐形成了我们自己的一套工作流程。比如如何是用git来管理我们的代码,如何用<code>git flow</code>来管理我们的代码提交流程。(如果你不是很熟悉这些,没有关系,我们会认真跟你讲明白,帮你尽快适应)。还有比如用trello来管理和追踪我们的工作进度和工作安排。</p>
<p>希望你可以尽快适应上述一切(那只是一部分),那是属于我们团队的特质(traits)。你在适应的过程中,可能会遇到一些困难,习惯上的,新语言上的。希望困难不会让你感到无所适从,但不管如何,请谨记下面最重要的一点。</p>
<p><code>养成认真、严谨的工作态度,对自己的工作成果负责。</code></p>
<p>要做到上述要求,你需要做到:</p>
<ol>
<li>在提交代码之前,认真检查自己的代码,没有任何多余无关的东西。</li>
<li>认真测试自己的输出成果,只有经过本地测试,内部测试之后,所有的东西才能发布在生产(production)环境。</li>
<li>希望你可以养成写单元测试的习惯,这样可以减少你犯错的机会。</li>
<li>不要重复犯低级错误。</li>
</ol>
<p>总而言之,就是对自己的成果负责,不要让其他人去发现你的低级的错误。请记住,这是最最重要的一点,如果你多次犯了这样的错误,我们对你会是零容忍的态度。(原则的事情需要说在前面,希望这样的事情永远不会发生)至于其他,语言,习惯上的,你可以慢慢适应。</p>
<p>最后,希望你可以在这里找到快乐。(Be Happy here).</p>
]]></content>
</entry>
<entry>
<title type="html"><![CDATA[Support Emoji in Rails 3.2.14]]></title>
<link href="http://creatingev.github.io/blog/2013/11/27/support-emoji-in-rails-3-dot-2-14/"/>
<updated>2013-11-27T09:29:23+08:00</updated>
<id>http://creatingev.github.io/blog/2013/11/27/support-emoji-in-rails-3-dot-2-14</id>
<content type="html"><![CDATA[<p>本文主要参考一片日文的文章<a href="http://qiita.com/ikm/items/7ac0c32c5264eac2b8bb">Rails 3.2でiOS5の絵文字を扱う</a>,实践并修改完成。让你的应用可以支持emoji,需要达到以下几点要求</p>
<ol>
<li>数据库支持emoji(utf8mb4)</li>
<li>rails的sql adapter可以支持以utf8mb4的方式访问数据库</li>
<li>传输过程中,utf8mb4的信息不会丢失</li>
</ol>
<h1>让MySQL数据库支持emoji(utf8mb4)的存储</h1>
<p>MySQL 5.5.3以上已经支持了utf8mb4的字符集,所以如果你的MySQL是5.5.3以上,只需要在my.conf文件中按照如下的配置就可以支持utf8mb4的字符集了。</p>
<pre><code>[client]
default-character-set = utf8mb4
[mysqld]
collation-server = utf8mb4_unicode_ci
character-set-server = utf8mb4
init_connect='SET NAMES utf8mb4'
</code></pre>
<p>在修改完my.conf配置之后,重启mysql,检查字符集是否已经更改,除了<code>character_set_system</code>和<code>character_set_filesystem</code>之外,其他的字符集都需要变成utf8mb4类型。</p>
<pre><code>mysql> show variables like 'char%';
+--------------------------+------------------------------------------------------+
| Variable_name | Value |
+--------------------------+------------------------------------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8 |
| character_sets_dir | /usr/local/Cellar/mysql/5.5.10/share/mysql/charsets/ |
+--------------------------+------------------------------------------------------+
</code></pre>
<p>为了支持之前用utf8创建的表同样支持emoji,你还需要将之前的表修改未utf8mb4字符集</p>
<pre><code>alter table posts convert to character set utf8mb4 collate utf8mb4_unicode_ci;
</code></pre>
<h1>rails支持emoji(utf8mb4)</h1>
<p>rails对utf8bm4的支持主要通过sql adapter实现,mysql2的0.3.13版本已经支持了utf8mb4 encoding。主要在配置(database.yml)的时候加上以下配置即可</p>