How to make your code imply responsibilities
saturnflyer.com
saturnflyer.com
The problem is not the boolean, it's that we're using the wrong name for the method. Just choose a better name:
class ProfilePresenter < ::Presenter
def display_experience?
profile.has_experience? && profile.experience_public?
end
end
The advantage of this over a block is that you can use this in more than one spot on the page. What if you wanted to show a special badge for users with experience in a different place? You'll end up extracting out this logic anyways -- it will just be hidden by another layer.> This leads us to the second problem: the intent of the method is to display features, not query for values. Were we to stick with a query method like has_public_experience? we would end up considering the content inside the view along with the meaning of the method every time we read this code.
When you move up and down the ladder of abstraction[1], make it clear. When you're talking about "has_experience? && experience_public?", the new name "with_experience" does not communicate that we're hiding details, nor does "block.call" when you look at the new method. The name "display_experience?" makes it clearer that we're now moving to a higher rung, the view.
https://en.wikipedia.org/wiki/Smalltalk#Control_structures
http://c2.com/cgi/wiki?VisitorPattern
https://en.wikipedia.org/wiki/Mogensen%E2%80%93Scott_encodin...
One neat example of this correspondence is continuation-passing style. For example, in Javascript:
function foo(){ return value; }
function fooCps(cb){ cb(value); }
function bar(){
if(x){
return {tag:'OK', value:value};
}else{
return {tag:'ERROR', errmsg:"message"};
}
}
function barCps(okCb, errCb){
if(x){
okCb(value);
}else{
errCb("message");
}
}It allows me to quickly recognize that something may or may not show up on the view.
I would prefer something along these lines:
class ProfilePresenter < ::Presenter
def with_experience?
profile.has_experience? && profile.experience_public?
end
end
<% if user_profile.with_experience? %>
<p><strong>Experience:</strong> <%= user_profile.experience %></p>
<% end %>I see how this code would be appropriate in larger apps but when things are just getting started. I would rather see an if else than having to go into three different structures to find out when a certain block of code is to be rendered.
... = function() {
// set up header
// set up content
// set up footer
};
Segregating the responsibilities might look something like: var homepage = (function() {
function renderHeader() {
// ...
};
function renderContent() {
// ...
};
function renderFooter() {
// ...
};
return {
renderHeader: renderHeader,
renderContent: renderContent,
renderFooter: renderFooter
};
})();
Now you can just invoke "homepage.renderHeader()", instead of, say, 5 different methods that conditionally decide what should go in the header.