Sunday, December 9, 2012

程式、設計與程式設計 - 流程圖 flowchart

程式、設計與程式設計 - 流程圖 flowchart

從大學一年級開始,我就常常被同學抓去問程式。不過,我從來不直接寫好程式給人家抄,都是要看到寫好的程式碼才會幫忙指出邏輯上的錯誤。(或是看到 註解,卻發現動作似乎不是那麼回事的程式碼。)拜此「只教你釣魚卻不給你魚」的邏輯之賜,漸漸的,來要作業的人少了,留下了真正想學東西的人。
最近跟同學吃飯的時候,聊到他們來問我程式的「感想」- 雖然被我冷嘲熱諷,但還是覺得有學到東西。尤其是最近程式越寫越大,聽到我說的一段話,覺得感觸良多:
「程式設計」為什麼叫做程式「設計」,就是因為重點在「設計」。否則它就會叫「程式撰寫」之類的東西了。
寫 程式如果不先設計,很容易花很多時間卻只寫出一個爛程式。你也許會認為,不設計可以節省時間,但是那是錯的。不先設計只會讓你寫到一半的時候不知道該怎麼 辦,然後花更多時間思考。卻又因為沒經過完整的設計,最後寫出一個不怎麼樣的(爛)程式。看著這個爛程式,你當然會想再花時間把它改好,卻因為沒有設計不 知該如何下手。但是這是你「已經」花了很多時間寫出來的程式,捨不得把它丟掉。於是花下比之前還多的時間下去除錯、增刪功能,最後還是做出一個不怎麼樣的 爛程式。然後你覺得它還是不夠好,可是又更捨不得把它丟掉(因為你已經為它付出太多了!),於是花下更多時間修改,然後更捨不得,然後修改,然後更捨不 得... 可是總歸要變成個爛程式,因為缺乏設計。死馬當活馬醫不是不行,但是可能會比直接換匹馬來的麻煩。就算真的醫好了,遇上你們這些實習醫生,這匹馬也不會變 的活跳跳,大概還是個半死不活的樣子,絕對不會比經過適當調教的健康馬跑的好。
所以,如果你們給我一個程式,我看了以後叫你重寫, 意思不是叫你直接去重寫,而是我覺得你必須重新設計你的邏輯,然後重寫。寫程式之前要先設計,是天經地義的道理。為什麼程式設計一開始要教流程圖?為什麼 計概一開始要教流程圖?為什麼組語一開始要教流程圖?都只是為了教你一套設計程式的方法。我不是說一定要畫什麼鬼流程圖,因為我自己也不畫那個東西,但是 至少要先設計過才開始寫程式。
後來,有位同學告訴我他的心得...
你知道第一次我來問你程式的時候,也是一直被罵「上課沒專心聽」、「去看課本第 xx 頁」之類的。也許當時我問的只是一些「for 迴圈怎麼用」或「switch ... case 的語法是什麼」的問題,上課老師一定教過、課本上也一定有。但是當時我只覺得「如果我上課都聽的懂、課本都看的懂,幹麻還來問你?」
後 來有一個比較大的作業,也是寫到一半拿來問你。當時你看了一眼程式碼以後,指著螢幕問我「這幾行程式碼在幹什麼?」的時候,我整個人傻掉,因為真的回答不 出來。當時你只說了「連你都不知道在作什麼的碼,寫它幹麻?」後來,你一點一點的改我的程式,一點一點告訴我哪裡可能該怎麼寫,一點一點把東西加進去,寫 出來的東西,我只覺得「這根本不是我寫的!」。
最後終於全部寫完、可以正確跑出結果,但是我還是霧煞煞。這個時候你又做了另一件讓 我吐血的事 - 把視窗整個關掉,跟我說「好啦!我已經告訴你該怎麼寫了,回去以後自己重寫一次。」當時我整個人抓狂,那是我花了三天才寫出來的東西,你看了兩個小時、改 了一堆東西以後叫我重寫?
後來我回去以後當然沒重寫,又抓著原來那塊半死不活的程式屍體改來改去,花了一個晚上,寫出了一個勉強可以跑,但是很多功能做不到的爛程式。當時的感覺,就真的是捨不得把它丟掉重寫一個。
突然之間,我終於知道為什麼新手容易寫出爛程式,除了技術功力以外,最根本的問題就是他們懶的作設計。許多老師在一開始給的都只是小程式 (Hello World!),幾乎一看就可以知道該怎麼寫,或是只要照著黑板抄就會跑,不需要什麼設計。很多時候,連為什麼要這樣寫都不知道。但是,隨著課程的深入, 依樣畫葫蘆已經不能作出作業。可是因為之前沒有設計解法的能力,所以想破頭也不知道該怎麼把答案弄出來。
後來繼續聊下去,發現大家都不知道該怎樣作設計才好。我是覺得,雖然有許多文章要你別再畫流程圖了,但是那是寫給已經畫過幾百張流程圖的老手看的,新手還是得從流程圖開始。所以,畫流程圖的時候...
  1. 不要超過一張 A4 紙(即使有那些「至下頁」的小圓點,你還是不會知道自己在畫些什麼的!相信我。)
  2. 不要過度詳細(如果一個方塊對一行程式碼,直接去寫就好了,別浪費時間畫圖。)
  3. 從 大問題開始畫起(例如,直接畫「程式開始 -> 擷取聲音 -> 傅立葉轉換 -> RLE 編碼 -> 赫夫曼編碼 -> 存檔 -> 結束」,別把 FFT、RLE、Huffman Encoding 到底怎麼做畫進同一張圖內。)
  4. 解決小問題(慢慢開始畫出怎樣開音效卡、怎樣收麥克風、讀進來的串流應該放在哪裡...)
  5. 照著畫出來的東西用手算一遍,看看有沒有邏輯錯誤。
  6. 把鍵盤拉過來開始打程式。
所以... 新手們...... 看看這篇文章,然後回去畫流程圖吧!!!

Reference:
http://palatis.blogspot.ca/2005/10/blog-post_30.html

Saturday, December 8, 2012

redirect all web traffic to a forward proxy server through Teamviewer VPN


Install Apache and set it as a forward proxy server

Eidt httpd.conf

### You can listen to multiple ports.
Listen 80
Listen 8080

LoadModule proxy_module modules/mod_proxy.so
LoadModule proxy_connect_module modules/mod_proxy_connect.so
LoadModule proxy_http_module modules/mod_proxy_http.so

# Virtual hosts
Include conf/extra/httpd-vhosts.conf

Edit httpd-vhosts.conf file:

### [START] add by Jun
NameVirtualHost *:80
NameVirtualHost *:8080



ProxyRequests On
ProxyVia On



    Order Deny,Allow
    Deny from All
    Allow from 127.0.0.1 192.168.178

    AuthType Basic
    AuthName "Password Required"
    AuthUserFile password.file
    AuthGroupFile group.file
    Require group usergroup



### [END] add by Jun

Create a password.file using the htpasswd.exe utility. Place it on the Apache Root directory

cmd> htpasswd.exe -c password.file username

Create a group.file using a text editor at the same level as the password.file with the following contents

usergroup: username

Install Teamviewer on both sever side and client side


1. download the latest Teamviewer (version 8.x and above).
http://www.teamviewer.com/download/TeamViewer_Setup_en.exe

2. Make sure you do enable the VPN option.

3. connect to your partner's teamviewer:
ID: 123 456 789
select "VPN" (make sure you do select this option, default is "Remote control".

Note: another way is to use "remote control" > extra tab at top bar > VPN > start.

4. a window will pop up, and you can see the partner's IP address. Copy the ip address.

5. Set up a proxy server for your browser:
go to start > run > Inetcpl.cpl > connections > LAN settings
> check "Use a proxy server for your LAN (These settings will not apply to dial-up or VPN connections)".
> Address (the partner's IP address from Teamviewer)
> Port 8080
> Click "Okay"

6. Done.


Reference:
http://stackoverflow.com/questions/724599/setting-up-an-apache-proxy-with-authentication


unresolved external symbol __imp__InitCommonControlsEx@4

unresolved external symbol __imp__InitCommonControlsEx@4

Solution 1:
project > right click > properties > configuration properties > linker > input > Additional dependencies > add ""

Solution 2:
You must have these two lines:

#include <commctrl.h>
#pragma comment( lib, "comctl32.lib" )

Reference:
http://bobobobo.wordpress.com/2008/02/14/troubleshooting-trackbar/

Thursday, December 6, 2012

<工作二三事> Leader is better than Manager


Leaders don't create followers, they create more leaders.
領導者不創造跟隨者,他們只是創造更多領導者。湯姆‧畢德士(Tom Peters)

我喜歡leader,不喜歡manager。
我喜歡follow leader,不喜歡follow manager。
我喜歡成為leader,不喜歡成為manager。
我喜愛被稱為leader,不喜歡被叫做manager。
我就是比較喜歡leader。

在我眼裡leader是正面的,是一種肯定的代名詞。而manager如果不是負面的,也頂多是平庸的。也許你不同意,不過不需要爭辯,因為這是我個人主觀的觀點。

Leader有能力成為manager,但是manager卻不一定能成為leader。

Leader是領導者,有leadership,有明確的目標,知道如何前進。
Leader會把大家一起帶到目的地,因為這是它的使命,跟著他,你會有安全感。
Leader會主動教導你,不會排擠你,跟著你,你知道你會學到很多。
Leader不是靠權力的,不會害怕你威脅到他的地位,很樂意給你機會,為你創造舞台,而你是會一直感念在心的。
Leader會陪你度過困難的時刻,你知道他會願意在第一時間伸出援手。
Leader以身作則,豎立榜樣,你知道他是你未來的目標。
Leader會在要求project schedule的同時,也注意你能從中學到什麼,每經過一件事,你就會感覺自己蛻變了一次。
Leader總是帶頭跑在前面,可是卻不會因為跑太快而棄你不顧,你會感覺到跟leader的差距而更加努力,而不會感到自卑、自憐或是否定自己。
Leader會幫助你找到價值的甜蜜點,協助你將你的價值發揮到極致。
Leader不會為了自己去犧牲別人,而是寧願犧牲自己去成就別人。

Manager就不多說了,如果manager不想成為leader,那只不過是權力的過客而已,因為權力來的快,去的也快。

總之,我喜歡leader,我喜歡follow leader,我喜歡成為leader,你呢?

Reference:

Bitwise Operators

In computer science, a mask is data that is used for bitwise operations, particularly in a bit field.

Using a mask, multiple bits in a byte, nibble, word (etc.) can be set either on, off or inverted from on to off (or vice versa) in a single bitwise operation.
http://en.wikipedia.org/wiki/Mask_%28computing%29
===

It's common to use the ``op='' shorthand forms when doing all of these operations:

flags |= DIRTY; /* set DIRTY bit */
flags &= ~OPEN; /* clear OPEN bit */
flags ^= VERBOSE; /* toggle VERBOSE bit */


SELECT  *
FROM    table
WHERE   field & number = number
-- to find values with superset of number's bits

SELECT  *
FROM    table
WHERE   field | number = number
-- to find values with subset of number's bits

http://en.wikipedia.org/wiki/Subset

===

18.2.1: Bitwise Operators

[This section corresponds to K&R Sec. 2.9]
The bitwise operators operate on numbers (always integers) as if they were sequences of binary bits (which, of course, internally to the computer they are). These operators will make the most sense, therefore, if we consider integers as represented in binary, octal, or hexadecimal (bases 2, 8, or 16), not decimal (base 10). Remember, you can use octal constants in C by prefixing them with an extra 0 (zero), and you can use hexadecimal constants by prefixing them with 0x (or 0X).
The & operator performs a bitwise AND on two integers. Each bit in the result is 1 only if both corresponding bits in the two input operands are 1. For example, 0x56 & 0x32 is 0x12, because (in binary):
0 1 0 1 0 1 1 0
 & 0 0 1 1 0 0 1 0
   ---------------
   0 0 0 1 0 0 1 0

The | (vertical bar) operator performs a bitwise OR on two integers. Each bit in the result is 1 if either of the corresponding bits in the two input operands is 1. For example, 0x56 | 0x32 is 0x76, because:
0 1 0 1 0 1 1 0
 | 0 0 1 1 0 0 1 0
   ---------------
   0 1 1 1 0 1 1 0

The ^ (caret) operator performs a bitwise exclusive-OR on two integers. Each bit in the result is 1 if one, but not both, of the corresponding bits in the two input operands is 1. For example, 0x56 ^ 0x32 is 0x64:
0 1 0 1 0 1 1 0
 ^ 0 0 1 1 0 0 1 0
   ---------------
   0 1 1 0 0 1 0 0

The ~ (tilde) operator performs a bitwise complement on its single integer operand. (The ~ operator is therefore a unary operator, like ! and the unary -, &, and * operators.) Complementing a number means to change all the 0 bits to 1 and all the 1s to 0s. For example, assuming 16-bit integers, ~0x56 is 0xffa9:
~ 0 0 0 0 0 0 0 0 0 1 0 1 0 1 1 0
   -------------------------------
   1 1 1 1 1 1 1 1 1 0 1 0 1 0 0 1

The << operator shifts its first operand left by a number of bits given by its second operand, filling in new 0 bits at the right. Similarly, the >> operator shifts its first operand right. If the first operand is unsigned, >> fills in 0 bits from the left, but if the first operand is signed, >> might fill in 1 bits if the high-order bit was already 1. (Uncertainty like this is one reason why it's usually a good idea to use all unsigned operands when working with the bitwise operators.) For example, 0x56 << 2 is 0x158:
0 1 0 1 0 1 1 0 << 2
   -------------------
   0 1 0 1 0 1 1 0 0 0
And 0x56 >> 1 is 0x2b:
0 1 0 1 0 1 1 0 >> 1
   ---------------
     0 1 0 1 0 1 1
For both of the shift operators, bits that scroll ``off the end'' are discarded; they don't wrap around. (Therefore, 0x56 >> 3 is 0x0a.)
The bitwise operators will make more sense if we take a look at some of the ways they're typically used. We can use & to test if a certain bit is 1 or not. For example, 0x56 & 0x40 is 0x40, but 0x32 & 0x40 is 0x00:
0 1 0 1 0 1 1 0   0 0 1 1 0 0 1 0
 & 0 1 0 0 0 0 0 0 & 0 1 0 0 0 0 0 0
   ---------------   ---------------
   0 1 0 0 0 0 0 0   0 0 0 0 0 0 0 0
Since any nonzero result is considered ``true'' in C, we can use an expression involving & directly to test some condition, for example:
if(x & 0x04)
  do something ;
(If we didn't like testing against the bitwise result, we could equivalently say if((x & 0x04) != 0) . The extra parentheses are important, as we'll explain below.)
Notice that the value 0x40 has exactly one 1 bit in its binary representation, which makes it useful for testing for the presence of a certain bit. Such a value is often called a bit mask. Often, we'll define a series of bit masks, all targeting different bits, and then treat a single integer value as a set of flags. A ``flag'' is an on-off, yes-no condition, so we only need one bit to record it, not the 16 or 32 bits (or more) of an int. Storing a set of flags in a single int does more than just save space, it also makes it convenient to assign a set of flags all at once from one flag variable to another, using the conventional assignment operator =. For example, if we made these definitions:
#define DIRTY 0x01
 #define OPEN 0x02
 #define VERBOSE 0x04
 #define RED 0x08
 #define SEASICK 0x10
we would have set up 5 different bits as keeping track of those 5 different conditions (``dirty,'' ``open,'' etc.). If we had a variable
unsigned int flags;
which contained a set of these flags, we could write tests like
if(flags & DIRTY)
  { /* code for dirty case */ }
if(!(flags & OPEN))
  { /* code for closed case */ }
if(flags & VERBOSE)
  { /* code for verbose case */ }
 else { /* code for quiet case */ }
A condition like if(flags & DIRTY) can be read as ``if the DIRTY bit is on''.
These bitmasks would also be useful for setting the flags. To ``turn on the DIRTY bit,'' we'd say
flags = flags | DIRTY;  /* set DIRTY bit */
How would we ``turn off'' a bit? The way to do it is to leave on every bit but the one we're turning off, if they were on already. We do this with the & and ~ operators:
flags = flags & ~DIRTY;  /* clear DIRTY bit */
This may be easier to see if we look at it in binary. If the DIRTY, RED, and SEASICK bits were already on, flags would be 0x19, and we'd have
0 0 0 1 1 0 0 1
 & 1 1 1 1 1 1 1 0
   ---------------
   0 0 0 1 1 0 0 0
As you can see, both the | operator when turning bits on and the & (plus ~) operator when turning bits off have no effect if the targeted bit were already on or off, respectively.
The definition of the exclusive-OR operator means that you can use it to toggle a bit, that is, to turn it to 1 if it was 0 and to 0 if it was one:
flags = flags ^ VERBOSE; /* toggle VERBOSE bit */

It's common to use the ``op='' shorthand forms when doing all of these operations:
flags |= DIRTY;   /* set DIRTY bit */
 flags &= ~OPEN;   /* clear OPEN bit */
 flags ^= VERBOSE;  /* toggle VERBOSE bit */

We can also use the bitwise operators to extract subsets of bits from the middle of an integer. For example, to extract the second-to-last hexadecimal ``digit,'' we could use
(i & 0xf0) >> 4
If i was 0x56, we have:
i    0 1 0 1 0 1 1 0
 & 0x56  & 1 1 1 1 0 0 0 0
     ---------------
     0 1 0 1 0 0 0 0
and shifting this result right by 4 bits gives us 0 1 0 1, or 5, as we wished. Replacing (or overwriting) a subset of bits is a bit more complicated; we must first use & and ~ to clear all of the destination bits, then use << and | to ``OR in'' the new bits. For example, to replace that second-to-last hexadecimal digit with some new bits, we might use:
(i & ~0xf0) | (newbits << 4)
If i was still 0x56 and newbits was 6, this would give us
i     0 1 0 1 0 1 1 0
 & ~0xf0   & 0 0 0 0 1 1 1 1
      ---------------
      0 0 0 0 0 1 1 0
 | (newbits << 4) | 0 1 1 0 0 0 0 0
      ---------------
      0 1 1 0 0 1 1 0
resulting in 0x66, as desired.
We've been using extra parentheses in several of these bitwise expressions because it turns out that (for the usual, hoary sort of ``historical reasons'') the precedence of the bitwise &, |, and ^ operators is low, usually lower than we'd want. (The reason that they're low is that, once upon a time, C didn't have the logical operators && and ||, and the bitwise operators & and | did double duty.) However, since the precedence of & and | (and ^) is lower than ==, !=, <<, and >>, expressions like
if(a & 0x04 != 0) /* WRONG */
and
i & 0xf0 >> 4  /* WRONG */
would not work as desired; these last two would be equivalent to
if(a & (0x04 != 0))
 i & (0xf0 >> 4)
and would not do the bit test or subset extraction that we wanted.
[The rest of this section is somewhat advanced and may be skipped.]
Because of the nature of base-2 arithmetic, it turns out that shifting left and shifting right are equivalent to multiplying and dividing by two. These operations are equivalent for the same reason that tacking zeroes on to the right of a number in base 10 is the same as multiplying by 10, and deleting digits from the right is the same as dividing by 10. You can convince yourself that 0x56 << 2 is the same as 0x56 * 4, and that 0x56 >> 1 is the same as 0x56 / 2. It's also the case that masking off all but the low-order bits is the same as taking a remainder; for example, 0x56 & 0x07 is the same as 0x56 % 8. Some programmers therefore use <<, >>, and & in preference to *, /, and % when powers of two are involved, on the grounds that the bitwise operators are ``more efficient.'' Usually it isn't worth worrying about this, though, because most compilers are smart enough to perform these optimizations anyway (that is, if you write x * 4, the compiler might generate a left shift instruction all by itself), they're not always as readable, and they're not always correct for negative numbers.
The issue of negative numbers, by the way, explains why the right-shift operator >> is not precisely defined when the high-order bit of the value being shifted is 1. For signed values, if the high-order bit is a 1, the number is negative. (This is true for 1's complement, 2's complement, and sign-magnitude representations.) If you were using a right shift to implement division, you'd want a negative number to stay negative, so on some computers, under some compilers, when you shift a signed value right and the high-order bit is 1, new 1 bits are shifted in at the left instead of 0s. However, you can't depend on this, because not all computers and compilers implement right shift this way. In any case, shifting negative numbers to the right (even if the high-order 1 bit propagates) gives you an incorrect answer if there's a remainder involved: in 2's complement, 16-bit arithmetic, -15 is 0xfff1, so -15 >> 1 might give you0xfff8shifted which is -8. But integer division is supposed to discard the remainder, so -15 / 2 would have given you -7. (If you're having trouble seeing the way the shift worked, 0xfff1 is 11111111111100012 and 0xfff8 is 11111111111110002. The low-order 1 bit got shifted off to the right, but because the high-order bit was 1, a 1 got shifted in at the left.)

Read sequentially: prev next up top
This page by Steve Summit // Copyright 1996-1999 // mail feedback


Reference:
http://www.eskimo.com/~scs/cclass/int/sx4ab.html

Tuesday, December 4, 2012

show column definition


mysql> SELECT column_name, data_type, character_maximum_length, column_comment FROM information_schema.columns WHERE table_name = 'TABLE_NAME';

mysql> SHOW FULL COLUMNS FROM tableName;

如何閱讀 Rails 原始碼


開始有計畫整理一些在 RubyConf China 大家線下問我的問題的答案。
挑選出來暫定的第一篇是大會期間詢問度最高的:「如何閱讀 Rails 原始碼」。
想要「閱讀 Rails 原始碼」的原因很多,不過多半的出發點都是想要能夠設計出更好的 Plugin (Gem)、或者是希望能在程式碼出錯時,能夠更快在 Rails 原始碼快速找到答案。
但擺在眼前的事實是, Rails 的原始碼已經成長大到成幾萬行的怪獸,如何「看懂」或者是有效率的找到答案,已經變成是一個很大的難題。
以下是我根據這幾年的經驗,能夠給各位的建議:

1. 從單純的部分切入,例如 Helper

最令大家頭疼的地方是,這麼多程式碼,要從哪部分開始讀起。
如果你是初心者,想要跳進這個池子裡,想找點簡單的東西讀,我會建議你先從「Helper」的部分開始讀。「Helper」是整個 Rails 程式碼裡面最獨立的部分(不牽扯到 request 呼叫),而且結構相對單純。

2. 從 request 開始,到 rack,到 routing,到 controller,最後再到 model

我真正開始有系統的讀懂 Rails code,是從一門線上 Owning Rails開始的。這門課的宗旨是,就是教你有效掌握搞懂 Rails 的核心與結構。相當有趣的是,他並不是教你讀任何 Rails 代碼,而是實際一步步帶你造出一個「mini Rails」。而造完這個 「mini Rails」之後,學員也能夠開始神奇的開始擁有快速找 code 的能力。
我在去年曾經寫過一篇 Owning Rails masterclass 介紹過這個課程。

第一天:造出自己的 mini Rails

帶你如何寫出精簡版 ActiveRecord、寫 rack app、用 rack app 改出精簡版 ActionController、自己 implement 出 before, after, around_ filter、自己 implement 出 view。然後最後再用你自己刻出來的這套 mini Rails 寫 web application。

第二天的課程

Refactor 昨天寫的 mini Rails,教你如何 trace Rails core。利用 Rails internal API 客製化出你想要的特殊 function、library。作業有 custom validator、custom finder、create responder、create form builder、使用 Railtie 客制 Engine、造 plugin。
宥於這是付費課程的關係,我也無法公開提供各位更進一步的教材內容。但是我能夠告訴各位這們課程為什麼會這樣設計,讓你可以也依循著這個軌道去自我進修。

rack

一個 request 進來,首先通過的是層層的 rack middleware。所以必須要先理解什麼是 rack,rack 的運作原理是什麼。可以試著自己先寫一個 rack app 玩看看。
如果想知道 Rails 裡面的 request 流程會經過哪些 middleware,被加過哪些工。可以在 Rails 專案裡面打 rake middleware,再去把 class 一個一個叫出來讀。

routing

request 通過 rack 層進來後,首先面對的是 dispatch 問題,Rails 透過 routes.rb 進行 dispatch。而如何 dispatch 到正確的 controller,中間靠的就是 regexp。

controller

開發者在 controller 會牽涉到兩個常用的相關機制:Filter 與 View Rendering。Filter 時怎麼運作的。method 應該是回傳「值」,怎麼做到自動回傳的是 render 出來的view。

model

ActiveRecord 的上一層就是一套 ActiveModel API。其實 Rails 不一定要靠 ActiveRecord,也可以透過實作一個 Class 加上部分機制做出自己的 ORM。其中 validation, finder 都是這方面的課題。

3. 搞懂 Rails 的啟動流程

RailsCast China 曾經 release 過一個很好的影片:The Rails Initialization Process By kenshin54
講解了整個 Rails 啟動流程。你也可以讀由 Ruby on Rails 官方釋出的這篇官方教學啟動流程去更加了解啟動過程中究竟會經過哪些檔案,如果要寫 plugin 可以 hook 在哪一些部分。

4. 實際簡單寫一個 Rails Plugin

最好的學習方法就是動手實作。在看過以上這一些資料之後,我建議你可以實際透過開發一個 Gem 去更加了解整個 Rails 內部的結構。
目前 Rails Plugin 幾乎都是以 Engine Gem 的形式釋出。所以透過撰寫一個 Gem,可以了解到:
  • 如何將自己的 Library 與現有 API 整合
  • 如何將自己的 Library / 不掛進啟動 process 中。
  • Engine 與 Railtie 的結構
  • 如果有相依檔案,如何撰寫 generator,把檔案放進去 project 裡面。
  • 如果有檔案操作和客製選項,如何透過 thor 這個工具去達到檔案修改的目的。
算是一個相當好的鍛鍊。

5. 讀別人(熱門)的 Rails Plugin

有時候,想要實作某一些功能不得其法。最好的方式就是去讀有類似功能的 Gem,去看看其他作者怎麼做的。有時候會翻到他們用了不少你根本不知道的 Rails API。
順著他們用這些 Rails API 的方法,可以更快的在 Rails 原始碼找到你要的答案…

小結

希望以上的方法能夠協助各位更快的上手讀通 Rails 的原始碼。有任何問題歡迎留言在底下討論。
Reference: