寫好軟件的訣竅


程序員身上的一個好笑的事情是,我們在畢生的職業生涯中都相信:我們的工作是告訴計算機如何去做。真實情況是,計算機能正確的按照命令去運行。無論你寫的是“Hello World”,還是用無人

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

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

 

訣竅
那麼,現在你想要知道這個簡單的祕訣,不是嗎?下面就是:

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

 

注意,我不是在討論明晰的代碼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

 

干擾,所有的這些回調和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

 

你可以看到它精煉的告訴了我們發生了什麼。這段代碼說,這個類有一個記錄創建者,一個編輯者,我們用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

 

所有的這些條件邏輯跟你的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

 

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

 

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

 

就這麼簡單。

 

來源:外刊IT

原文:The Trick To Good Software

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章