As a pasionate software developer, motivated by learning and appliyng innovative and interesting software development tools, techniques and methodologies, my professional objectives are the following. To be in a technology oriented enterprise where the technichal staff is the soul of the company. To be in an important IT team. Be able to design and develop state of the art software. Be able to apply new knowledge everyday, on innovative ways and with a great degree of freedom. To architect, design and develop software that uses the best practices of the field. Play with the latest technologies, learn everyday and participate in the research and innovation of the software products. Carlo is a DZone MVB and is not an employee of DZone and has posted 15 posts at DZone. You can read more from them at their website. View Full User Profile

Making Rich Domain Models in Ruby is Better than in Java

03.05.2012
| 6696 views |
  • submit to reddit

Being a Java developer starting to do some programing in Ruby i found many different nice things in the language and the way things are done.

One of the nicest things i found is the notion of module mixing, and although you can artificially do the same with Java and Spring (google for @DeclareParents) , it’s not as neat and clean as Ruby does it.

Module mixins basically allow us to add behaviour to our objects without inheritance. Is like if in Java we could use an Interface that has a default behaviour associated to it, so we don’t need to actually implement the methods of the interface.

The objects that has the module mixed in, can receive method calls on the module like if the methods belong to the object itself. This allows to a nice approach to domain rich programming, while at the same time maintaining a great separation of concerns and avoiding filling the classes and objects with lots of not very related functionality.

To explain the last paragraph better, let’s take a simple example. a Person class.

In our example a person can have emotions (happy, sad, etc), can do actions (play, sleep), have measure attributes and queries(height,weight). It can also be used in database operations (If we want like an ActiveRecord approach) (save, update, etc).

In a Model centric approach (Instead of using services, DAOs, etc) we would like to have Person objects that allow us to do thing like:

    if (person.sad?)
     
    person.playWith(toy)
     
    if (person.higher_than?(person2))
     
    person.store

We can consider each of these methods addressing different concerns, but all valid thing for a Person to know about. if we were to program this with Java, we would end up with a Person class with all these methods like:

    public class Person{
        public boolean isSsad(){...}
        public void playWith(Toy toy){...}
        public int store(){...}
        public boolean isHigherThan(Person person2) {...}
    }

  We could argue that a better approach would be to have “behavioural” modules and plug them individually to our class. For example in Ruby we could have something like:

    class Person
       include Sentiments
       include Actions
       include Persistence
       include Measures
    end

 We can have then each module dealing with its own concern, and making all this knowledge and capacities available to the Person objects as if they were defined on the Person class.

So for example our “Measures” module could have something like:

    module Measures
      attr_accesor :height  
      def higher_than?(entity)
       return self.height > entity.height
      end
    end

  Then we can do something like:

    a= Person.new
    a.height = 150
    b=Person.new
    b.height=200
     
    b.higher_than? a

 Source: http://cscarioni.blogspot.com/2011/03/making-rich-domain-models-in-ruby-is.html

Published at DZone with permission of Carlo Scarioni, author and DZone MVB.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Oleg Kozlov replied on Mon, 2012/03/05 - 7:28pm

I like Ruby, this is probably my favorite dynamically-typed programming language. The mixin feature looks pretty flexible and allows programmers to do neat tricks like described above.

However, in my opinion this is a good example of how easy it is to develop difficult to maintain software, and why you have to be extra careful to be able to build reliatively serious/complex systems. 

Imagine a new developer joining a team and trying to figure out behavior of one of the domain objects constructed with mixins and the code for those domain objects spread among half a dozen different files? The destruction of productivity can be pretty significant.

 Once a program grows over, say, 20-30 thousand lines of code and once you have to implement complicated algorithms using the domain objects - maintaining it will become pretty difficult, especially for people not originally involved in development of this code.  

 This issue could typically be solved with the help of tools (IDE) that would help developers to link various files that contain code for a given domain object, but that's not easy to achieve for dynamically typed languages where IDEs have to guess half the time (incorrectly) each variable type... Also, you have to consider how many people still use command line or basic non-Ruby-aware text editors to develop code...  

 my 2 cents.. 

Cej Hah replied on Mon, 2012/03/05 - 7:51pm

If I'm going to build a rich domain model with methods like "playWith(Toy toy)", I'm sure not going to muck it up by adding in DB operations like "int store()". That's not a "Model centric approach", that's just abusing the single responsibility principle. In other words, DB operations aren't part of having a rich domain.

Edvin Syse replied on Tue, 2012/03/06 - 2:50am

Java 8 will probably get defender methods, ie. interfaces can reference default implementations for methods :)

Carlo Scarioni replied on Tue, 2012/03/06 - 4:59am

Hi Cej Hah,

 As you can see from the example, the code in the Ruby version is completely clean thanks to the Mixins. 

In Java I wouldn't add the store method to the class either, and that is the point of the post, that Java doesn't allow you to do this in a clean way. You can be a believer or not in the ActiveRecord model but the fact is that Ruby gives us this extra fleixibility where you can have your core class, and Mix In different behaviours to it in a clean an unobtrusive way.

 Even if you don't consider the store method, because you don't like the Active Record pattern, having to define all unrelated methods in your class (for every different interface you implement) isnot the best.

About your single responsibility observation. In Ruby there is a module with the single responsibility of persistence. The core class is delegating its store operation implicitly to the module when it is mixed in the class.

Carlo Scarioni replied on Tue, 2012/03/06 - 6:57am in response to: Oleg Kozlov

Hi Oleg,

 

I think that a complex system will be complex no matter what language you use.

Let's say for example in Java (which is the language I use the most in evruday work). You will still need the code to persist your objects, you will still need the code to all the behaviours you need. You may have to implement many interfaces, you may have to depend upon many collaborators.

 In my experience having the code in the different modules help to better undestand the code and where to look for something so I don't think that having more files with their responsibilities clear is in any way worst for productivity than having a huge file that does everything, totally  the opposite in my opinion.

Also if the modules are included at the beginning of the class file, you know exactly where to look for the the functionalities.

Raphael Miranda replied on Tue, 2012/03/06 - 7:35am

The same way we don't make methods with thousands of LoC or classes with thousands of LoC, one shouldn't develop massive applications with dozens of thousands of LoC.

Break down your problem and create well defined applications focused on solving mind-grasping objectives than compose the total solution out of them. 

Massive complex applications with multiple weakly tied concerns will be overly complex and hard to maintain in any language or framework.  

Russel Winder replied on Tue, 2012/03/06 - 7:51am

Shouldn't the comparison be Groovy vs Ruby rather than Java vs Ruby?

Carlo Scarioni replied on Tue, 2012/03/06 - 8:46am in response to: Russel Winder

Hi Russel,

The comparison is simply based on the two programming languages I use the most. Mixins are in no way just in Ruby, Scala also have a similar feature with Traits, so you can argue that the comparison should be with Scala.

So as I said, I work in Java at work, I go home and try things with Ruby, and this is how I developed the comparison. I could say great things about Java not in Ruby, this is in no way a post against Java, it is just to see how a different language (Ruby in this case) solves some particular problems in a nicer way than Java.I don't know what is wrong in realizing that a different language than the one you use all the time can have advantages that you are not aware of (with 'you' I mean we the whole development community).

Cej Hah replied on Tue, 2012/03/06 - 11:09am in response to: Carlo Scarioni

Carlo,

I don't consider the Ruby mixins to be completely clean because methods such as "store()" still show up all the time.  If you really wanted to do something like that, Scala does an awesome job by being able to add Traits at instantiation time.  For example "val p = new Person with Persistence" or "val p = new Person" 

Carlo Scarioni replied on Wed, 2012/03/07 - 4:38am in response to: Cej Hah

Hi Cej, I don't know exactly what you mean with the "store() show up all the time" can you please explain...

On the other hand, Ruby allows you to include modules at Runtime using the extend method on a particular instance:

car = Car.new

car.extend(Movable)

The Movable module will only be included in the particular car instance.

Jaffa Wify replied on Sat, 2012/07/21 - 5:02am in response to: Oleg Kozlov

Prepare to prosecute a domestic violence case by compiling evidence of mistreatment. This can include everything from photos of bruises to detailed accounts of psychological abuse. The more comprehensive your information, the better your chances of winning a conviction. Thanks a lot. Regards, debt relief

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.