iT邦幫忙

2023 iThome 鐵人賽

DAY 14
1
自我挑戰組

富士大顆系列 第 14

vol. 14 Rails Super DRY :程式界的 YOLO 態度、OAOO(到底多愛縮寫這群人!)

  • 分享至 

  • xImage
  •  

你好,我是富士大顆 Aiko
今天來談談 什麼是 DRY 以及有哪些方式可以進行


一次且僅一次(Once and only once) 又稱為 DRY(Don't Repeat Yourself)是一個軟體開發中非常重要的概念,也是敏捷開發 Agile 的核心,特別是在 Ruby on Rails 等框架中。DRY 原則的主要目的是減少重複的程式碼,以提高軟體的可維護性、可讀性和可重用性。這裡有幾種常用的方法來實踐 DRY:

1. 方法(Methods)與函數(Functions)

像 Ruby 這種動態語言(Dynamic Language)中,方法和函數的重用性非常強,能有效地實踐 DRY 原則,將重複的程式碼片段封裝成方法或函數,然後在其他地方呼叫這個方法。所謂的動態語言有幾個強項:
--1.Runtime Modifications 執行時動態地改變物件的結構,更多的彈性使用可重用的程式碼。
--2.Type Inference 不用特別聲明變數的類型,執行時自動推斷,這樣就更容易寫出可重用的函數或方法。

封裝(Encapsulation)是一個物件導向程式設計(Object-Oriented Programming, OOP)的基本概念,用於將資料(屬性)和與之相關的行為(方法)包裝在單一的單位或物件中,在 Ruby 也就是 block(從 def 到 end 中間的那些)。在實踐 DRY 原則的過程中,封裝通常用於將重複的程式碼片段組織成單一的、可重用的方法或函數。這樣,當需要修改這段代碼時,只需要在一個地方進行修改,從而提高了可維護性和可讀性。

def calculate_area1
  3.14 * 5 * 5
end

def calculate_area2
  3.14 * 10 * 10
end

同樣的邏輯算法重複了,可以改成:

def calculate_area(n)
  3.14 * n * n
end

2. 繼承(Inheritance)

通過繼承,子類可以重用父類中的方法和屬性。

class Father
  def make_money
    puts "I like money"
  end
end

class Son < Father
end
son.make_money
#"I like money"

3. 模組(Modules)和混入(Mixins)

模組(Modules)

在 Ruby 裡,模組(Modules)主要是用來封裝(Encapsulation)相關的方法、常量(Constant,全大寫,初始化後就不建議改變,rails 會提出警告)等,以便能夠重用這些程式碼片段。模組不能被實體化(Instantiate),也就是不能建立一個模組的實體。

module MyModule
  def a_method
    "doing sth"
  end
end

instance = MyModule.new
#這樣會噴錯:`NoMethodError`

namespace:

puts MyModule::a_method
#這種情況下會出錯,因為 a_method 是一個實例方法,不能這樣直接調用

直接使用模組名稱來調用模組方法:

module MyModule
  def self.a_method
    "doing sth"
  end
end

# 使用模組名稱來使用
puts MyModule.a_method  
#"doing sth"

類別(非模組)被實體化:

module MyModule
  def a_method
    "doing sth"
  end
end

class MyClass
  include MyModule
end

instance = MyClass.new
puts instance.a_method  
#"doing sth"

但可以把模組「混入(Mix in)」到類別(Classes)或其他模組中。

混入(Mixins)

混入是一種在不使用繼承(Inheritance)的情況下,將一個模組的功能加入到一個或多個類別的方法。這是 Ruby 中實現多重繼承(Multiple Inheritance)的一種方式。可以使用 includeextend 這兩個關鍵字來進行混入(Mixins)
-include
會將模組(Module)中的方法加入到類別(Class)的實體方法中。也就是需要實體化(Instantiate)該類別的物件才能使用這些方法。

module Greetable
  def greet
    puts "Hello, I'm a module method."
  end
end

class Person
  include Greetable
end

p = Person.new
p.greet  # 輸出 "Hello, I'm a module method."

-extend
將模組中的方法加入到類別的類別方法中,或者將模組中的方法加入到單個物件的單件方法(Singleton Methods)中。

module ClassMethods
  def class_greet
    puts "Hello, I'm a class method."
  end
end

class Person
  extend ClassMethods
end

Person.class_greet  # 輸出 "Hello, I'm a class method."
差別 include extend
作用域 (scope) 把模組的方法作為實例方法加入類別中 把模組的方法作為類別方法加入
調用方式(Invocation) 需要通過類別的實體來調用 直接透過類別來使用
用途(Usage) 當你希望模組中的方法能在多個類的實例中重用 把一個模組的方法加入到單個物件中,或者作為類別方法加入到整個類中。

ActiveSupport::Concern

在 Rails 中,ActiveSupport::Concern 模組提供了一個更加簡化和標準化的方式來創建和使用混入。使用 ActiveSupport::Concern,可以更容易地管理依賴和程式碼組織。

# app/models/concerns/nameable.rb
module Nameable
  extend ActiveSupport::Concern

  included do
    validates :name, presence: true
  end
end

這裡定義了一個名為 Nameable 的模組。這個模組使用 ActiveSupport::Concern,並在被其他類別引用(Include)後,會自動執行 included 塊內的程式碼。

# app/models/user.rb
class User < ApplicationRecord
  include Nameable
end
#少寫validates :name, presence: true

在這裡,User 類別引用了 Nameable 模組。這意味著 User 類會繼承 Nameable 模組中定義的所有方法和功能。在這個例子中,User 類會自動獲得一個名字(name)的驗證,要求名字必須存在(presence: true)。

這種方式允許你將共享的邏輯(例如,名字的驗證)抽取出來,並封裝在一個模組中,然後再混入到需要這些功能的類別中。當你需要更改某個邏輯或功能時,只需在一個地方進行更改,而不是在多個地方進行更改,這大大減少了出錯的機會和減輕了維護的負擔,這樣就達到了 DRY(Don't Repeat Yourself)的目的。

4. 過濾器(Filters)與回呼(Callbacks)

在 Rails 控制器或模型中,使用像 before_action 這樣的過濾器或回呼,以在執行某些動作之前或之後運行特定的程式碼。能讓我們在不同的動作(Actions)之間共享邏輯,這也是 DRY 的一種實現。

# app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
end

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  # authentication will run first due to inheritance
end

5. Strong Parameters

為了增加安全性,對重複出現的參數過濾可以抽取出一個方法。能讓我們在一個地方定義參數過濾邏輯,然後在多個地方重複使用。

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  private

  def user_params
    params.require(:user).permit(:username, :email, :password)
  end
end

6. 部分視圖(Partial Views)

在視圖中,如果有重複的 HTML 結構,可以使用部分視圖來重用這些結構。這在前端開發中是一個常見的 DRY 實踐,尤其是在使用像 ERB 這種模板語言時。
重複使用的畫面:

<!-- app/views/shared/_header.html.erb -->
<header>
  <!-- header content -->
</header>

其他畫面想用:

<!-- app/views/layouts/application.html.erb -->
<%= render 'shared/header' %>

這些方法讓 DRY 原則可以都有效地應用在 Ruby on Rails 的開發中,
使用這些 DRY 的實踐方式或概念,可以讓你的 Ruby、SQL 或 JavaScript 程式碼更加乾淨、有組織,也更易於團隊合作。

無論你是專注於後端還是前端,或者全端工程師,掌握和運用 DRY 原則都是非常重要的。
一起super DRY 起來~~


上一篇
vol. 13 Rails 的精髓 MVC 架構:不只是概念還有用法,專案開發不再害到人
下一篇
vol. 15 Rails 的導航員:routes.rb 「請往這邊走哦!」(上)
系列文
富士大顆30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言