Подготовил Владимир Суворов
SLA - single level of abstraction. Принцип единого уровня абстракций.
Чтобы повысить читаемость кода, мы пишем код на том уровне абстракции, который приемлем для его понимания без умственных затрат на вникание в реализацию.
Когда уровни абстракций смешаны.
# spec/features/user_marks_todo_complete_spec.rb
feature "User marks todo complete" do
scenario "updates todo as completed" do
sign_in # Норм
create_todo "Buy milk" # Норм
# А ниже уже похуже :)
find(".todos li", text: "Buy milk").click_on "Mark complete"
expect(page).to have_css(".todos li.completed", text: "Buy milk")
end
def create_todo(name)
click_on "Add new todo"
fill_in "Name", with: name
click_on "Submit"
end
end
(defn instruction-for-info
[info instructions]
(let [default
(get instructions :default "default message not found")]
(or
(->> instructions
(filter (fn [[k _]] (.startsWith info (name k))))
first
last)
default)))
feature "User marks todo complete" do
scenario "updates todo as completed" do
sign_in
create_todo "Buy milk"
mark_complete "Buy milk"
expect(page).to have_completed_todo "Buy milk"
end
def create_todo(name)
click_on "Add new todo"
fill_in "Name", with: name
click_on "Submit"
end
def mark_complete(name)
find(".todos li", text: name).click_on "Mark complete"
end
def have_completed_todo(name)
have_css(".todos li.completed", text: name)
end
end
(defn prefix-match [target-str pairs]
(some
(fn [[k v]]
(if (.startsWith target-str (name k))
v
false))
pairs))
(defn instruction-for-info
[info instructions]
(let [default
(:default instructions "default message not found")]
(or
(prefix-match info instructions)
default)))
Принцип единственной обязанности (Single responsibility principle)
Каждый сущность должна иметь одну обязанность и эта обязанность должна быть инкапсулирована.
class Student
attr_accessor :first_term_home_work, :first_term_test,
:first_term_paper
attr_accessor :second_term_home_work, :second_term_test,
:second_term_paper
def first_term_grade
(first_term_home_work + first_term_test + first_term_paper) / 3
end
def second_term_grade
(second_term_home_work + second_term_test + second_term_paper) / 3
end
end
class Student
def initialize
@terms = [ Grade.new(:first), Grade.new(:second) ]
end
def first_term_grade
term(:first).grade
end
def second_term_grade
term(:second).grade
end
private
def term(reference)
@terms.find {|term| term.name == reference}
end
end
class Grade
attr_reader :name, :home_work, :test, :paper
def initialize(name); @name = name; end
def grade
(home_work + test + paper) / 3
end
end
(defn display-records []
(let [records (sql/query "SELECT * FROM ...")
record-string (str/join "\n" (for [r records]
(str (:first-name r) (:last-name r) (:id r))))]
(println record-string)))
(defn fetch-records []
(sql/query "SELECT * FROM ..."))
(defn record->string [record]
(str (:first-name record) (:last-name record) (:id record)))
(defn records->string [records]
(str/join "\n" (map record->string records)))
(defn display-records []
(-> (fetch-records)
records->string
println))
Принцип инверсии зависимостей (англ. Dependency Inversion Principle, DIP) — принцип, используемый для уменьшения связанности в компьютерных программах.
class Report
def initialize
@body = "whatever"
end
def print
XmlFormatter.new.generate @body
end
end
class XmlFormatter
def generate(body)
# convert the body argument into XML
end
end
class Report
def initialize
@body = "whatever"
end
def print(formatter)
formatter.generate @body
end
end
class XmlFormatter
def generate(body)
# convert the body argument into XML
end
end