Source: Saturn Flyer Blog

Saturn Flyer Blog The 4 Rules of East-oriented Code: Rule 1

4 simple rules are pretty easy to remember, but a bit harder to understand and apply.A key concept of East-oriented Code is to enforce the use of commands by returning the object receiving a message.Here's a simple example of what that looks like:def do_something # logic for doing something omitted... self endIt's incredibly simple to follow.Here are the rules I set forth in my presentation at RubyConf:Always return selfObjects may query themselvesFactories are exemptBreak the rules sparinglyThe first three are hard rules. The fourth, obviously, is more lenient. We'll get to some guidance on breaking the rules in the future but for now let's look at applying this to your code.Rule 1: Always return selfAlthough this rule is simple at first, it inevitably leads to the queston of getter methods.What if your objects had no getters? What if an object's name attribute simply was inaccessible to an external object?You can make your data private by either marking your attr_accessors as private:attr_accessor :name private :nameOr you can use the private method to mark all of the following defined methods to be private:private attr_accessor :nameHow you choose to do it will depend upon your code, but this would help you remove any getter methods.Now this leaves you with a conundrum. How do you use the information?If you have a need for that name, what can you do?The only answer is to create a command which will apply the data to the thing you need.def apply_name_to(form) form.name = name self endThe restricitions we put in our code are often self-imposed.We can make whatever we want, so what's to stop us from putting Rails model data manipulation in it's view template? Nothing concrete stops us from doing so.The same goes for getter methods like name. If it is publicly accessible by external objects, then we can create whatever if and case statements we want. We can put logic wherever we want.If we create our own restrictions, we can guide ourselves and other programmers to the direction we intend for our application's structure.Creating restrictionsI've written about the Forwardable library in the past not only because of it's usefulness, but because we can copy the same pattern to create our own DSL.Forwardable provides methods which create getter methods for related objects. But what if we created our own DSL for commands to related objects? What if we could pass the messages on, but allow the related object to handle the values?Here's what that could look like:class Person command :send_email => :emailer end person = Person.find(1) # get some record person.emailer = Emailer.get # get some object to handle the emailing person.send_emailThat's a lot of pseudo-code but the parts we care about are sending the command to a related object. Commands return the receiving object, queries will return a value.Here's what that code would look like without our (yet unimplemented) command DSL.class Person def send_email emailer.send_email self end endAny code which uses a Person will have to rely on the command to do its own thing. This prevents a programmer from leaking logic out of the person.What should happen when the email is sent? With the structure above, this code, can't make decisions:if person.send_email # do one thing else # this will never work now endIf you find that you often write code like the if statement above, you might wonder "where does that logic go now?" Now, you'll be forced to write this code:person.send_emailAnd this means that your send_email now has the job of handling what to do:class Person def send_email emailer.send_email # do some other things... self end endThat might provide you with better cohesion; the related behaviors remain together.Getting back to that command DSL we used above...This was the final point of my presentation at RubyConf: you can build guidlines like this for yourself.I created a gem called direction to handle enforcing this East-oriented approach. I'll write more about that later, but it shows that I can create signals to other developers on my team. I can take a simple concept like a command and simplify my code to show other developers what's happening:class Person command :send_email => :emailer endBuilding a DSL can aid in communication. The language and terminology we use can compress ideas into easily digestible parts.If you like this, check out my new book: Ruby DSL Handbook designed to be a guide to help you build your own compressions of concepts.

Read full article »
Est. Annual Revenue
$25-100M
Est. Employees
25-100
CEO Avatar

CEO

Update CEO

CEO Approval Rating

- -/100