Hacker News new | past | comments | ask | show | jobs | submit login
How to make your code imply responsibilities (saturnflyer.com)
38 points by saturnflyer on Oct 21, 2013 | hide | past | favorite | 9 comments



> First, the name merely combines two values. What will happen when requirements change and we need to ensure that the provided experience includes at least 3 years of activity? The meaning of has_public_experience? will change along with its behavior and lead to surprises for developers unfamiliar with these particular details. It will no longer merely be existince of experience allowed for the public.

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.

[1] http://worrydream.com/LadderOfAbstraction/


Thanks for some fantastic feedback. I haven't read the worrydream link yet, but will check it out.


This is a neat trick that pops up from time to time. Instead of representing an algebraic data type as a bunch of cases that you can test with if-statements at runtime, you represent it as a pattern-matching function that receives a code block to run for each possibility.

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");
       }
    }


This is only necessary because the templates he's using are so crude and page-oriented. With a truly object-oriented framework like Wicket the problem goes away - you have a component hierarchy that parallels your model hierarchy, so e.g. your user panel just knows that a user has an address and hobbies etc., then the address panel just knows that it has a street name component and a zip component and so on. I wish I could find a framework that was properly object-oriented in any other language.


Personally the 'if' conditional statement acts as a visual trigger.

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 %>


Great read and use of blocks.

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.


This is a great article. I'm brainstorming how to do this in javascript.


Right now, you might have something like:

    ... = 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.


thanks! I'd love to see what you do




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: