Saturday, 24 July 2010

Ditching the Service Layer and IOC for Mxins in Ruby

I still classify myself as very new to Ruby on rails, although I like many other .NET developers are annoying the life out of other people by droning on about how great the brave new(?) world of Ruby is.  Before I start, if anyone disagrees with what I am about to post here then please, please, please write a comment below that explains a better approach.

I have been developing in .NET since framework beta 1 (doesn't everyone say that) since 1892.  I like many, (or so it seems) .NET developers are looking at other frameworks and platforms like Ruby on Rails due to a frustration with the continuous abominations coming out of Microsoft like RIA services, oData, Entity Framework, Worflow, Silverlight etc.  Microsoft continually wants to lower the bar to lesser developers and all this does is....attract lesser developers who offer nothing back.  I find myself just hating everything.  I also find myself getting angry at the constant ill appropriated blog posts about Domain, Driven Design and other nonsense like CQRS that fill up my RSS reader from the better educated .NET developers.  Am I alone in thinking that DDD is just impractical for 99% of all the applications that it is used in and the blue book was pretty dull?  I still enjoy C# but the surrounding patterns, practices and new features just really annoy me now.  I cannot work out if I am truly this enamoured with Ruby on Rails or is it that it is just different. I am probably just hankering after something new and shiny and Ruby on Rails ticks all the new and shiny boxes for me.  I find the dynamic paradigms fascinating and I have been pouring over the source of things like the Rails ORM ActiveRecord for an idea of how to do things differently.  The source of ActiveRecord is crazy, crazy, crazy but I do have a better understanding of just what shape shifting is available in a dynmaic language now.  One thing, I really do not want to do is to start coding in a Ruby on Rails application, just like I was coding a .NET application.  What would be the point?  I want to fully explore what a dynamic language has to offer and why so many Java developers before us felt the need to move here. 

I am working on a MicroIsv project in my spare time and I came across an interesting decision today which has lead me to this post.  My infant product will scrape text from a yellow pages like directory website and then go through a data scrubbing process to make sense of the unstructured data.  I could write the data scrubber myself but I would have to start delving into natural language processing or other time consuming concepts that would probably mean postponing the release date of the application to one that stretches beyond my lifetime.  Thankfully there are a number of 3rd party webservices, REST webservices or whateverwebservices that can unburden me of this somewhat difficult task.  I do not want to favour one just now and I also want to leave the option of changing provider if and when I feel the need.  I also do not want to call the service from my unit tests for all the reasons that are usually trotted out for calling external resources with unit tests.  The obvious thing to do is to isolate this functionality.

If I was doing this in .NET, I would create a service layer that is defined by an inteface for the requested service just like below:

    1 public interface IDataScrubber

    2 {

    3     Lead ScrubData(Dictionary<string, object> parts);

    4 }


I would then autowire this service into the IOC container of my choice that would inject the service via constructor injection into a controller or something where I would use it.  This allows me to mock the service and also depend on an interface rather than the concrete implementation. 

While looking at a lot of the Ruby source code that I have installed in the form of RubyGems on my hard drive, I just do not see this type of implementation.  There are no interfaces in Ruby for starters and you rarely see an IOC container although they do exist.  This has led me to seek a way that takes advantage of the flexibility of a dynamic languages.  As I said previously, I see little point in writing this application in Ruby as if it were a static language like C#.  I want to try to comprehend the power and malleability of a dynamic language.

The first approach does not lean on any dynamic magic, I am just going to suggest using default parameters that are part of Ruby.  I can simply suggest a default implementation in the constructor of the Parser class below.  Initialize is the constructor of a Ruby object if you did not know.


    1 class Parser

    2     attr_reader :scrubber

    3 

    4     def initialize(scrubber = DataScrubber.new)

    5         @scrubber = scrubber

    6     end

    7 end

    8 

    9 class DataScrubber

   10     #real implementation goes here

   11 end



That is ridiculously easy and for simple cases, there is no reason not to use this approach, what could be simpler.  In the constructor of Parser, I have a default parameter for the scrubber member variable.  This will create the real DataScrubber if none other is offered when creating an instance of Parser.  When testing, I can simply create the parser with a stubbed out version of the DataScrubber.

I still do not feel satisfied by this answer and next I want to look at mixins.  From what I can tell in Ruby, it seems they use fewer classes than other OO languages like C#.  In C# we tend to compose things through a lot of small classes that run under the guise of Separation of Concerns.  The problem with this is that there is generally a lot of implementation details needed when creating these interwoven class structures.  Hence we have the IOC container to take away this complex creation process that often exists.
With Mixins, we can implement behaviour in one module that gets mixed into one or more classes that should have that behaviour.  A good way to ensure that the concerns are, in fact separated is to develop the mixins in a test driven manner.    

We could define our DataScrubber in a module like this:

    1 module DataScrubber

    2   def self.included(base)

    3     puts "module included by #{base}"

    4   end

    5 

    6   def scrub_data(parts = {})

    7     parts.keys.each{|p| puts "doing something with #{parts[p]}"}

    8   end

    9 end


Note, I am using the hook method included above that fires whenever it is included by another object.  The hook method here is purely for illustration but it is useful to know it is there.


This then allows me to test the mixin in isolation like this by mixing it in to a simple empty instance

    1 class MixinTest < ActiveSupport::TestCase

    2 

    3   test "should test DataScrubber" do

    4     scrubber = Class.new

    5 

    6     scrubber.instance_eval do

    7       include DataScrubber

    8     end

    9    

   10     scrubber.scrub_data({:one => "one", :two => "two"})

   11    

   12     #assert behaviour here

   13   end

   14 

   15 end


Here I am creating a blank instance of an object and passing a block or anonymous method to instance_eval which will evaluate a block in the context of the instance.  You can add, override and modify object instances at runtime using instance_eval which is part of Ruby's dynamic playground.  I like this approach because we are not having to create a plethora of classes to add behaviour and I can test the behaviour in isolation.  If you have ever looked into creating Mixins in .NET then you will know how difficult a task this is.


When it comes to running a unit test against the Parser class that has this functionality mixed in via the include statement, I somehow want to stub out this behaviour when the DataScrubber is mixed into the Parser class like it is below:

    1 class Parser

    2   include DataScrubber

    3

    4   def parse()

    5     parts = {:one => "one", :two => "two"}

    6 

    7     scrub_data(parts)

    8   end

    9 

   10   def initialize   

   11   end

   12 end

 
As ruby is a dynamic language, this is very easy, here is one way of doing this:

    1   test "should stub out DataScrubber" do

    2     parser = Parser.new

    3 

    4     parser.instance_eval do

    5       undef scrub_data  #not strictly necessary

    6

    7       def scrub_data(parts)

    8         puts "stubbed out method"

    9       end

   10     end

   11 

   12     parser.parse

   13   end

 

Here I am using our old friend instance_eval to open up the parser instance and undefine the scrub_data method that has been mixed in before re-adding it with the behaviour that I want to run in my tests without having to call the 3rd party service.

Of course any modern platform is defined by the number of mocking frameworks on offer and Ruby certainly has plenty,
flexmock is my weapon of choice and below is an example of how I could use flexmock to create a partial mock to return some test data:

 

    1   test "should stub out DataScrubber" do

    2     parser = Parser.new

    3 

    4     flexmock(parser).should_receive(:scrub_data).and_return { "some data"}

    5 

    6     result = parser.parse

    7 

    8     #assert result data

    9   end

 
The last approach I am going to mention is inheriting from ActiveResource. I am not sure this is appropriate to me as the service must understand Rails-style URLs and I might not have that luxury with whatever 3rd party service provider, I choose.

I think mixins are the right choice for me, the Ruby way seems to be (and I could be wrong, I regularly am) to create lots of methods as opposed to interwoven class structures that require complex object creation techniques, just to get to the functionality you require.

If I was approaching this problem in C#, I would say, "I would isolate this functionality in a service that I inject into the controller" but in Ruby, I would say "I would write this as a Ruby module that I include in my class".

Testing, stubbing or mocking are, as is often stated, ridiculously easy.


It is funny to note that when I was musing about this earlier on twitter somebody who describes himself in his bio as a "passionate Rubyist" made the following questionable comment "Composing services with mixins? Ouch, enjoy the impending doom.".  I suspect this guy is like me, a .NET developer who now suddenly thinks he is a "rubyist".  Another thought is that perhaps real Ruby on Rails guys are thinking of moving onto Clojure or Scala, now that Ruby is no longer as hip as it was.


10 comments:

  1. Full disclosure I write C# for cash money, and really enjoy the framework.

    Looking at your examples Mixins seem to be a difficult or perhaps obtuse way of simulating an interface in Ruby. To me the C# service layer is a cleaner design, made extremely flexilbe by using DI. Am I missing something??

    ReplyDelete
  2. I am not trying to simulate an interface.

    Being able to do away with something as complex as an IOC container is a big bonus to me.

    Part of the reason I use an IOC container in .NET is that mocking the services is easier that way.

    I still definitely advocate an IOC container in C# but there really is no need in Ruby.

    This is just not needed in a dynamic language.

    ReplyDelete
  3. I'm very new to dynamic thinking, but I'm not sure if you're trying to make Ruby behave more like a static language by using mixins. You're initial example when you just instantiate an object of type datascrubber is surely the true power of dynamic programming. If I had a new DataScrubber implementation then could I not override your base implementation and then instantiate my custom code as needed.

    From the outside looking in, it seems to me that the Ruby way of doing things is pragmatic and driven by You Ain't Going to Need It (YAGNI) philosophy. Complex "enterprise" thinking appears to be generally frowned upon.

    ReplyDelete
  4. My first example has with the default parameter has nothing to do with dynamic languages and has eveything to with......default parameters. No dynamic magic here.

    As I stated in the article, the Ruby way seems to be to use more methods, rather than lots of small classes which do one thing.

    Mixins are generally difficult in static languages which makes them not really a viable option. Mixins are piss easy in Ruby and are therefore used widely from what I can tell.

    I am not sure why you say I am trying to get Ruby to behave statically by using them or why you quote YAGNI.

    ReplyDelete
  5. I guess I'm trying to get to the bottom of what advantages you see in implementing the code in Ruby over using C#. Is it simply that you don't need an IOC container, or do you think the Ruby code is more maintainable or inherently better in some way?

    I quote YAGNI because Ruby folks seem to have a kind of Zen like relationship with their code, that it must be as elegant as possible. Ie the Ruby Way.

    ReplyDelete
  6. For me, Rails is one of the biggest pulls rather than the Ruby language. Although a lot of the magic in Rails is possible thanks to Ruby's metaprogramming constructs.

    Also the Ruby community is strong with Gems for everything and a lot more people willing to contribute rather than just use Open Source.

    As far as a Zen like relationship with their code goes, there is just as much bad code as there is on other platforms. There are a lot of PHP hackers in the Ruby space so do not believe the hype that it is all pure.

    ReplyDelete
  7. since 1892? wow! :)

    Anyway - i think You underestimate domain driven design a bit. it's not about those damn patterns. it's about way You handle business problems through exposing them explicitly. but yeah, CQRS is quite an overhead (despite that there are some great bonuses like no need for uber denormalized database and ORM).

    First time i saw mixins I finally get what 'composition over inheritance' actually means. In .NET i still can't understand in most cases how to remove inheritance chains.

    Closest thing in .NET to mixins is tagging classes with interfaces and writing extension methods for them. But that's quite unnatural and far from perfect.

    ReplyDelete
  8. If you are developing any application in asp.net then it will become more complex to find the bugs and errors.SO online software testing is the option to make it more easy.
    -online testing

    ReplyDelete
  9. No smart developer that cares about good OOD would write a serious app in RoR. RoR's place is to develop stupid little applications.

    ReplyDelete
  10. INTERNATIONAL CONCEPT OF WORK FROM HOME
    Work from home theory is fast gaining popularity because of the freedom and flexibility that comes with it. Since one is not bound by fixed working hours, they can schedule their work at the time when they feel most productive and convenient to them. Women & Men benefit a lot from this concept of work since they can balance their home and work perfectly. People mostly find that in this situation, their productivity is higher and stress levels lower. Those who like isolation and a tranquil work environment also tend to prefer this way of working. Today, with the kind of communication networks available, millions of people worldwide are considering this option.

    Women & Men who want to be independent but cannot afford to leave their responsibilities at home aside will benefit a lot from this concept of work. It makes it easier to maintain a healthy balance between home and work. The family doesn't get neglected and you can get your work done too. You can thus effectively juggle home responsibilities with your career. Working from home is definitely a viable option but it also needs a lot of hard work and discipline. You have to make a time schedule for yourself and stick to it. There will be a time frame of course for any job you take up and you have to fulfill that project within that time frame.

    There are many things that can be done working from home. A few of them is listed below that will give you a general idea about the benefits of this concept.

    Baby-sitting
    This is the most common and highly preferred job that Women & Men like doing. Since in today's competitive world both the parents have to work they need a secure place to leave behind their children who will take care of them and parents can also relax without being worried all the time. In this job you don't require any degree or qualifications. You only have to know how to take care of children. Parents are happy to pay handsome salary and you can also earn a lot without putting too much of an effort.

    Nursery
    For those who have a garden or an open space at your disposal and are also interested in gardening can go for this method of earning money. If given proper time and efforts nursery business can flourish very well and you will earn handsomely. But just as all jobs establishing it will be a bit difficult but the end results are outstanding.

    Freelance
    Freelance can be in different wings. Either you can be a freelance reporter or a freelance photographer. You can also do designing or be in the advertising field doing project on your own. Being independent and working independently will depend on your field of work and the availability of its worth in the market. If you like doing jewellery designing you can do that at home totally independently. You can also work on freelancing as a marketing executive working from home. Wanna know more, email us on workfromhome.otr214423@gmail.com and we will send you information on how you can actually work as a marketing freelancer.


    Internet related work
    This is a very vast field and here sky is the limit. All you need is a computer and Internet facility. Whatever field you are into work at home is perfect match in the software field. You can match your time according to your convenience and complete whatever projects you get. To learn more about how to work from home, contact us today on workfromhome.otr214423@gmail.comand our team will get you started on some excellent work from home projects.


    Diet food
    Since now a days Women & Men are more conscious of the food that they eat hence they prefer to have homemade low cal food and if you can start supplying low cal food to various offices then it will be a very good source of income and not too much of efforts. You can hire a few ladies who will help you out and this can be a good business.

    Thus think over this concept and go ahead.

    ReplyDelete