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
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.
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.
Full disclosure I write C# for cash money, and really enjoy the framework.
ReplyDeleteLooking 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??
I am not trying to simulate an interface.
ReplyDeleteBeing 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.
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.
ReplyDeleteFrom 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.
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.
ReplyDeleteAs 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.
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?
ReplyDeleteI 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.
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.
ReplyDeleteAlso 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.
since 1892? wow! :)
ReplyDeleteAnyway - 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.
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.
ReplyDelete-online testing
No smart developer that cares about good OOD would write a serious app in RoR. RoR's place is to develop stupid little applications.
ReplyDeleteNice post ! Thanks for sharing valuable information with us. Keep sharing..
ReplyDeleteRuby on Rails Online Training India
lab cabinet manufacturer
ReplyDeleteworld777 bet
best tution classes in gurgaon
Flats in Jaipur
cloudkeeda
what is azure
azure free account
azure data factory
A Dedicated Server requires an operating system that is compatible with the server hardware and the applications or services.
ReplyDeleteElevate your online presence with powerful singapore dedicated server. Experience unmatched performance and reliability for your business needs.
ReplyDeleteEscape to a luxurious best resort in jaipur, where royal elegance meets modern comfort. Enjoy world-class amenities, serene landscapes, and unforgettable experiences.
ReplyDelete