寫好軟件的訣竅

jopen 11年前發布 | 4K 次閱讀 軟件

寫好軟件的訣竅
程序員身上的一個好笑的事情是,我們在畢生的職業生涯中都相信:我們的工作是告訴計算機如何去做。

真實情況

真實情況是,計算機能正確的按照命令去運行。無論你寫的是“Hello World”,還是用無人飛機去殺死一個人。計算機都能精確的按照你的命令去做。

可我們的工作,我們的真正工作是:告訴程序員和我們自己:我們讓計算機做什么了。現代的軟件編程思想就是結構化的、清楚的描述計算機將要執行的任務。

事實上,計算機并不去閱讀你在程序里寫了什么,而人會。計算機把程序員寫的代碼編譯成字節比特,真正會去看你寫的是什么的只有人類。

寫軟件要像講故事

如果你對你的工作和你寫的代碼的行為有了新的認識,你會馬上很清楚的發現,編程工作更像講故事。

想一想。你是如何知道一個人講故事沒人愛聽的?這很簡單,他老跑題,他老是糾結在不重要的細節上,他老是在故事場景中挑來跳去,等等。你立刻能知道故事被他講爛了。

雖然在最后你能明白故事里發生了什么,你甚至能復述它,但你會喜歡這樣的故事嗎?你會有興趣轉述給別人或豐富故事內容嗎?

相同的事情也發生在軟件開發中。如果你的代碼寫的含糊不清,亂七八糟,沒有人會愿意欣賞它。沒有人會愿意看它第二次。并且你是第一個受它折磨的人。

訣竅

那么,現在你想要知道這個簡單的秘訣,不是嗎?下面就是

代碼里的干擾因素越少越好

</blockquote>

注意,我不是在討論明晰的代碼vs隱晦的代碼,不是在討論約定優先,不是在討論元數據編程有害或其它類似的東西。

寫出好的軟件的訣竅是代碼里只寫那些能讓你的代碼講出的故事更有意義的內容。如果它能讓你的代碼更清楚,那就這樣寫它。如果這個東西對故事沒有任何意義,那就扔了它。扔了它能讓故事更好。如果代碼耦合模塊不清,就用元數據編程和約定。

例子

有一些經典的例子可以證明這一點。比如,描述一篇帖子和它的作者的關系。

class Post < ActiveRecord::Base
  belongs_to :author, class_name: 'User', foreign_key: :authored_by
end

看見了沒?所有關于類名,外鍵的信息都是干擾。去掉它們。

class Post < ActiveRecord::Base
  belongs_to :user
end

第二版中沒有好聽的“作者”字眼,但卻是更優的,因為它直奔主題,用最簡短的語句告訴所有你想知道的。

另外一個例子,說一個類需要關聯那些創建/修改它的信息的用戶

class Setting < ActiveRecord::Base
  belongs_to :creator
  belongs_to :editor

attr_accessor :editing_user

before_create :set_creator before_update :set_editor

private

def set_creator self.creator = @editing_user end

def set_editor self.editor = @editing_user end

end</pre>

干擾,所有的這些回調和attr_acessors都是干擾,都是垃圾信息,沒有任何價值體現在你想完成的任務中。更簡潔更好的方法是下面這樣寫:

class Setting < ActiveRecord::Base
  belongs_to :creator
  belongs_to :editor

def editing_user=(user) if new_record? self.creator = user else self.editor = user end end end</pre>

你可以看到它精煉的告訴了我們發生了什么。這段代碼說,這個類有一個記錄創建者,一個編輯者,我們用editing_user賦給它們值。沒有回調干擾。沒有幾個private方法的無用信息。

一個更經典的例子。在controller里管理數據

class PostsController < ApplicationController
  def create
    if params[:post][:text].present?
      if params[:post][:text] =~ /fuck|cock|shit/
        flash[:error] = "Be nice"
        @achtung = true
      end
    end

if !@achtung
  @post = Post.new(params[:post])

  if @post.save
    flash[:success] = "Yoo hoo!"
    redirect_to :index
  else
    render :new
  end
else
  redirect_to :index
end

end end</pre>

所有的這些條件邏輯跟你的controller實際上沒有任何關系。所有的這些邏輯判斷并不屬于controller層負責。當然,你可以這樣做,而其能正常的運行,但這不是好的軟件。

試試這樣寫

class PostsController < ApplicationController
  def create
    @post = Post.new(params[:post])

if @post.save
  flash[:success] = "Yoo hoo!"
  redirect_to :index
else
  render :new
end

end end

class Post < ActiveRecord::Base validate :bad_language_check

private

def bad_language_check if text =~ /fuck|shit|cock/ errors.add(:text, "has some pretty bad language") end end end</pre>

現在你的controller能清楚的說明白發生了什么。你可以清楚的看明白當記錄可以創建和不能創建時會發生什么。跟Post類一樣,你可以清楚的理解它在過濾那些不干凈的文字。而且校驗器有自己單獨的地方。它的實現方式不會影響Post本身。

結論

其實很簡單。想寫出好的軟件嗎?別再給機器寫代碼,從此后為人寫代碼。

就這么簡單。

 

[英文原文: The Trick To Good Software ]
 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!