I find methods/functions decomposed into three parts really satisfying. Consider a typical xUnit test:
def test_grants_new_role
# setup
user = make_user
new_role = make_new_role
# behavior under test
user.add_role(new_role)
# assert results
assert_equal [new_role], user.roles
end
Lately I’ve been structuring Rails controller similarly:
def create
# Extract inputs/parameters from HTTP request
person_params = params.require(:person).permit(:name, :age)
# Invoke behavior encapsulated in a Plain(ish) Ruby object somewhere
user = UserService.create_user(person_params)
# Check the result and make some HTTP output
if user.persisted?
redirect_to user_path(user.id)
else
@user = user
render :new
end
end
Clojure even has the let
form which encourages this style:
; annotated from clj-http
; https://github.com/dakrone/clj-http/blob/master/src/clj_http/util.clj
(defn gzip
"Returns a gzip'd version of the given byte array."
[b]
(when b
; set the table
(let [baos (ByteArrayOutputStream.)
gos (GZIPOutputStream. baos)]
; do the work and clean up
(IOUtils/copy (ByteArrayInputStream. b) gos)
(.close gos)
; produce a result
(.toByteArray baos))))
I don’t think there’s anything inherently wrong if a method or function isn’t organized this way. But when I read code structured this way, it feels less like a bunch of random logic and more like a cohesive unit that someone put time into thinking through how someone might try to understand it later. The Rule of Three rules everything around us.