做軟件也要走“捷徑”。程序員身上的一個(gè)好笑的事情是,我們在畢生的職業(yè)生涯中都相信:我們的工作是告訴計(jì)算機(jī)如何去做。
真實(shí)情況
真實(shí)情況是,計(jì)算機(jī)能正確的按照命令去運(yùn)行。無論你寫的是“HelloWorld”,計(jì)算機(jī)都能精確的按照你的命令去做。
可我們的工作,我們的真正工作是:告訴程序員和我們自己:我們讓計(jì)算機(jī)做什么了?,F(xiàn)代的軟件編程思想就是結(jié)構(gòu)化的、清楚的描述計(jì)算機(jī)將要執(zhí)行的任務(wù)。
事實(shí)上,計(jì)算機(jī)并不去閱讀你在程序里寫了什么,而人會(huì)。計(jì)算機(jī)把程序員寫的代碼編譯成字節(jié)比特,真正會(huì)去看你寫的是什么的只有人類。
寫軟件要像講故事
如果你對(duì)你的工作和你寫的代碼的行為有了新的認(rèn)識(shí),你會(huì)馬上很清楚的發(fā)現(xiàn),編程工作更像講故事。
想一想。你是如何知道一個(gè)人講故事沒人愛聽的?這很簡單,他老跑題,他老是糾結(jié)在不重要的細(xì)節(jié)上,他老是在故事場景中挑來跳去,等等。你立刻能知道故事被他講爛了。
雖然在最后你能明白故事里發(fā)生了什么,你甚至能復(fù)述它,但你會(huì)喜歡這樣的故事嗎?你會(huì)有興趣轉(zhuǎn)述給別人或豐富故事內(nèi)容嗎?
相同的事情也發(fā)生在軟件開發(fā)中。如果你的代碼寫的含糊不清,亂七八糟,沒有人會(huì)愿意欣賞它。沒有人會(huì)愿意看它第二次。并且你是第一個(gè)受它折磨的人。
訣竅
那么,現(xiàn)在你想要知道這個(gè)簡單的秘訣,不是嗎?下面就是
代碼里的干擾因素越少越好
注意,我不是在討論明晰的代碼vs隱晦的代碼,不是在討論約定優(yōu)先,不是在討論元數(shù)據(jù)編程有害或其它類似的東西。
寫出好的軟件的訣竅是代碼里只寫那些能讓你的代碼講出的故事更有意義的內(nèi)容。如果它能讓你的代碼更清楚,那就這樣寫它。如果這個(gè)東西對(duì)故事沒有任何意義,那就扔了它。扔了它能讓故事更好。如果代碼耦合模塊不清,就用元數(shù)據(jù)編程和約定。
例子
有一些經(jīng)典的例子可以證明這一點(diǎn)。比如,描述一篇帖子和它的作者的關(guān)系。
1 classPost<ActiveRecord::Base
2 belongs_to:author,class_name:'User',foreign_key::authored_by
3 end
看見了沒?所有關(guān)于類名,外鍵的信息都是干擾。去掉它們。
1 classPost<ActiveRecord::Base
2 belongs_to:user
3 end
第二版中沒有好聽的“作者”字眼,但卻是更優(yōu)的,因?yàn)樗北贾黝},用最簡短的語句告訴所有你想知道的。
另外一個(gè)例子,說一個(gè)類需要關(guān)聯(lián)那些創(chuàng)建/修改它的信息的用戶
01 classSetting<ActiveRecord::Base
02 belongs_to:creator
03 belongs_to:editor
04
05 attr_accessor:editing_user
06
07 before_create:set_creator
08 before_update:set_editor
09
10 private
11
12 defset_creator
13 self.creator=@editing_user
14 end
15
16 defset_editor
17 self.editor=@editing_user
18 end
19
20 end
干擾,所有的這些回調(diào)和attr_acessors都是干擾,都是垃圾信息,沒有任何價(jià)值體現(xiàn)在你想完成的任務(wù)中。更簡潔更好的方法是下面這樣寫:
01 classSetting<ActiveRecord::Base
02 belongs_to:creator
03 belongs_to:editor
04
05 defediting_user=(user)
06 ifnew_record?
07 self.creator=user
08 else
09 self.editor=user
10 end
11 end
12 end
你可以看到它精煉的告訴了我們發(fā)生了什么。這段代碼說,這個(gè)類有一個(gè)記錄創(chuàng)建者,一個(gè)編輯者,我們用editing_user賦給它們值。沒有回調(diào)干擾。沒有幾個(gè)private方法的無用信息。
一個(gè)更經(jīng)典的例子。在controller里管理數(shù)據(jù)
01 classPostsController<ApplicationController
02 defcreate
03 ifparams[:post][:text].present?
04 ifparams[:post][:text]=~/fuck|cock|shit/
05 flash[:error]="Benice"
06 @achtung=true
07 end
08 end
09
10 if!@achtung
11 @post=Post.new(params[:post])
12
13 if@post.save
14 flash[:success]="Yoohoo!"
15 redirect_to:index
16 else
17 render:new
18 end
19 else
20 redirect_to:index
21 end
22 end
23 end
所有的這些條件邏輯跟你的controller實(shí)際上沒有任何關(guān)系。所有的這些邏輯判斷并不屬于controller層負(fù)責(zé)。當(dāng)然,你可以這樣做,而其能正常的運(yùn)行,但這不是好的軟件。
試試這樣寫
01 classPostsController<ApplicationController
02 defcreate
03 @post=Post.new(params[:post])
04
05 if@post.save
06 flash[:success]="Yoohoo!"
07 redirect_to:index
08 else
09 render:new
10 end
11 end
12 end
13
14 classPost<ActiveRecord::Base
15 validate:bad_language_check
16
17 private
18
19 defbad_language_check
20 iftext=~/fuck|shit|cock/
21 errors.add(:text,"hassomeprettybadlanguage")
22 end
23 end
24 end
現(xiàn)在你的controller能清楚的說明白發(fā)生了什么。你可以清楚的看明白當(dāng)記錄可以創(chuàng)建和不能創(chuàng)建時(shí)會(huì)發(fā)生什么。跟Post類一樣,你可以清楚的理解它在過濾那些不干凈的文字。而且校驗(yàn)器有自己單獨(dú)的地方。它的實(shí)現(xiàn)方式不會(huì)影響Post本身。