A question for Rubyists

I was checking out this post from Derick Bailey today, and something struck me rather odd.  Not the “DI only enables testability” argument, but the ruby code:

class Foo
    def bar
     baz = Baz.new
     baz.do_something
   end end

I’ve been very curious to see what real Ruby applications look like written by real Rubyists.  From the code I’ve seen, Ruby code written by C# developers looks vastly different than Ruby code written by seasoned Ruby developers.  For example, I can’t really recall ever seeing something like “Baz.new” on anything that wasn’t a Model object or other primitive.

From what I’ve seen, composition in Rails apps happens more through modules and duck-typing, rather than new’ing up a dependency.  In the above example, the Baz type doesn’t have any state, so there’s not really a reason to instantiate it at all.

This is the piece that I always question when I see code like this.  In Rails production apps I’ve had the privilege of seeing, Dependency Injection was never necessary simply because there weren’t any dependencies to begin with.  At most there were some modules/duck typing for static services like encryption.  Otherwise, it just didn’t happen.

So a question (or two) for Rubyists:

  • Would you ever write the above code in the first place?
  • In one sentence (ha ha), how do you apply SOLID to your Ruby applications?

I’m working under the assumption that SOLID principles still apply, but in just far different ways.  From my JavaScript experience, I’ve seen that SOLID and OO are still important, but they’re applied much differently, so I assume the same holds true for Ruby.

Related Articles:

Post Footer automatically generated by Add Post Footer Plugin for wordpress.

About Jimmy Bogard

I'm a technical architect with Headspring in Austin, TX. I focus on DDD, distributed systems, and any other acronym-centric design/architecture/methodology. I created AutoMapper and am a co-author of the ASP.NET MVC in Action books.
This entry was posted in C#, Rails. Bookmark the permalink. Follow any comments here with the RSS feed for this post.
  • http://www.lostechies.com/members/derick.bailey/default.aspx derick.bailey

    tangent: since you asked on twitter, here’s the list of books that Scott recommended for getting into Ruby. they should help you discover / answer some of these questions.

    Scott’s list:
    ——

    A good place to start for someone coming from C# is probably a look at something that both languages have in common but do differently. Since the example in you message above was patterns-related, you might try the book, Design Patterns in Ruby:

    http://www.amazon.com/Design-Patterns-Ruby-Russ-Olsen

    Dave Thomas’ screencast series is quite enlightening as well. It goes from very basic ideas in Ruby through some rather mind-boggling examples of meta programming:

    pragprog.com/…/the-ruby-object-model-and-metaprogramming

    There’s also a great Socratic-style book on Ruby from Pragmatic Programmers that is a good page-turner from beginner and beyond:

    http://www.pragprog.com/…/metaprogramming-ruby

    Here’s a video of a presentation I did at the NDC about Ruby for .NET devs, but it is mostly a regurgitation of Dave Thomas’ videos (but with a dose of shock value to wake up those lethargic .NET identities in the audience:

    http://vimeo.com/12803005

    ————-

    also – i think i have a fair understanding of how SOLID applies to ruby at this point. i’ll probably do a blog post on it since it will involve code samles.

    and you’re right – that is lousy ruby code. i specifically wrote that code in that way so that i could have a 1 to 1 comparison of the c# example code right next to it.

  • Rob Conery

    I’m not a Rubyist – but I’ve learned enough to answer (sort of) … and I also know my answer could get me yelled at. MINSWAN!

    Anyway – I don’t like to use one class from within another. I just refactored that out today with a ShoppingCart sample I’m writing. Typically, in C# you would pass in (in AddToCart) the user and the product along with the quantity.

    With Ruby you can just pass a hash – this unties the class dependencies completely:

    user.add_to_cart(:sku => “sku”, :price => 1, :quantity => 2)

    In looking at this it might seem like I’ve tied cart functions to a User – but I haven’t. I’m using the Tekpub::Shopper module which contains these methods:

    class User

    include Tekpub::Shopper
    #…

    end

    I really like the “type-free” way of passing arguments; it also helps readability from the calling end (at the expense of being a bit verbose).

  • http://pedroreys.com Pedro Reys

    Jimmy,

    Fabio Kung has a nice post on DI on Ruby where he shows the usage of Modules to do DI.

    http://fabiokung.com/2010/05/06/ruby-and-dependency-injection-in-a-dynamic-world/

    On the comments of his post there is also some discussion on if it is really IoC or only DI that modules help to solve.

  • nieve

    in the comments to derick’s post, the usage of modules has been mentioned as one way of doing DI in ruby. i would really love to see what happens inside this module and how exactly does it know at runtime what is it expected to do…
    Are there any other ways to do DI in ruby that would be considered as a good practice? And if so, what are the differences or implications of choosing one over the other?

  • Andrew Stewart

    Hi

    Here’s a question the example Rob shows us, below:

    =======================
    With Ruby you can just pass a hash – this unties the class dependencies completely:

    user.add_to_cart(:sku => “sku”, :price => 1, :quantity => 2)

    looking at this it might seem like I’ve tied cart functions to a User – but I haven’t. I’m using the Tekpub::Shopper module which contains these methods:

    class User
    include Tekpub::Shopper
    #…
    end
    end

    =======================

    Ok so maybe it’s me, but could we do this in c# with

    user.AddToCart(new { Sku = “sku”, Price = 1, Quantity = 2});

    public partial class User
    {
    public void AddToCart(dynamic itemToAdd) // send in an anonymous object
    {
    }
    }

    Alternatively could we achieve the same abstraction as Fabio Kung suggests using an extension method.

    In other words, is it possible not that the problem isn’t that ruby is more powerful than c#(which it is a little – meta programming). It’s that the solution’s they use are generally condemned in .net.

  • nieve

    Ok, so my question re the module implementation was redundant…

    @Andrew, i think using extension methods won’t work as module since you declare the using MyExtensions when calling the method, so that if you call it inside your extended class, you could use only one implementation.

  • http://novembermeeting.blogspot.com/ Mitin Pavel

    >> Dependency Injection was never necessary simply because there weren’t any dependencies to begin with.

    Class names of activerecord classes are dependencies.

    But most rails developers don’t even think about the problem. The reason is: RoR pushes us toward DataDrivenDevelopment. From this point of view the AR classes are rigid, and irreplaceable. So developers don’t even think, one can inject this classes or stub them.

  • http://ampgt.com Scott Bellware

    Jimmy,

    Let’s pretend that the baz in Derick’s example is a dependency, and that it has all the stuff it needs to qualify it as such.

    The answer to your question is a resounding “yes”, this is a perfectly fine way to deal with this dependency. There are other circumstances that might not make the exact same code perfectly fine. It depends entirely on what else is adjacent, and whether the surroundings are sufficiently transparent.

    Here’s another thing that’s perfectly fine in Ruby while being absolutely anathema in C#: the Singleton pattern.

    I told that one to Bob Martin over coffee with Seb Lambla, Mike Feathers, and Roy Osherove. Bob was almost incredulous. Not quite – but almost.

    The way that you think about a class when your mind has made the cultural switch to Ruby isn’t the way you think about a class in C# – except for those parts of the thinking that are common between the two.

    If you don’t except that language shapes thinking, then all of this is a non-starter.

    Ultimately, Rob Conery’s example doesn’t sit well with me. Ultimately, I’m passing in an abstraction that more or less responds to :sku, :price, and :quantity. Sure, the calling semantics are different, but essentially the same. That is, IN ESSENCE, it’s the same. In purpose and intention, it’s the same. From the client’s perspective, it’s the same (that’s “client”, as in Client-First Development, or “TDD”). If I were using a Hash that uses method missing to forward calls to its dictionary, I could use Rob’s hash exactly as I would any other object: hash.sku, hash.price, and hash.quantity. At that point, it might as well be: order_line.sku, order_line.price, and order_line.quantity.

    If were were talking about the same code in Lua: hash.sku, etc, is how to index into a hash by default in that language. Same for JavaScript.

    Rob said, “I don’t like to use one class from within another”, but Rob is kinda playing a bit of mental self-trickery here, because the argument passed to “user.add_to_cart(:sku => “sku”, :price => 1, :quantity => 2)” is indeed an instance of a class. It’s an instance of the Hash class. So… no avoiding the uses of classes from other classes – especially in Ruby where there’s no such thing as something that doesn’t derive from a class.

    So what’s the real principle in play here?

    For me, I have no idea what the principle is. What I really think is happening here might actually be some of Rob’s deeply-engrained C# culture trumping the somewhat newly-minted Ruby culture.

    If the add_to_cart method creates an instance of OrderLine with the values passed in as an instance of Hash, I might just go ahead and just pass in order_line instead. Or, I might allow passing in both, making the add_to_cart method a message dispatcher rather than a message processor. If the cart object stores Hash values, it may not be a meaningful-enough abstraction. Hard to see without looking at the fullness of the implementation so that its specific circumstances can be understood.

    To answer the specific question about SOLID in Ruby: I would apply SOLID exactly as it should be applied in Ruby – from a Ruby perspective. You’re only going to get that perspective from spending enough time in Ruby to become aware of your C# biases. It’s likely enough that it will be a much bigger “Holy Shit!” moment than you’re expecting.

    Here’s some code that might be a bit more idiomatic

    class Foo
    def bar
    baz.do_something
    end

    def baz
    @baz ||= Baz.new
    end
    end

    The goal is Inversion of Control. Dependency Injection is just a mechanism of Inversion of Control, and usually one that lives colloquially in static, class-oriented languages.

    What’s being “inverted” in Inversion of Control? The control that’s inverted is the control over where the dependency is instantiated.

    Here’s some Inversion of Control of Foo’s baz instance:

    foo = Foo.new
    foo.instance_eval do
    @baz = OtherBaz.new
    end

    Or this:

    foo = Foo.new
    def foo.baz
    @baz ||= OtherBaz.new
    end

    But this is all pretty raw. It doesn’t take long to find meaningful abstractions for this kind of configuration. And ultimately, it’s configuration code. A DSL might be handy here as well. And maybe something more general that meta-programs these mechanisms into place.

    These are naive examples. They’re meant to show a couple of underlying mechanisms that permit control to be inverted using the language. There are others. Depends on what you’re doing.

    What’s missing here is the container, but the language itself is so amenable to the essence of the pattern that a container is rarely needed – unless you’re writing a framework stack. And then – only maybe. But if you jump into Ruby and decide that the first thing you’ll do is write yourself an application stack, you’re probably just masturbating compulsively. There’s more off-the-shelf open source for Ruby stacks right now than will probably ever exist for a .NET stack. This is the “ecosystem”. It’s possible because plugin systems are a lot easier to create and use when the plugin mechanism isn’t a data type, and when the plugin can modify the membrane of the cell it’s integrating into.

    The big hurdle here is how you’re accustomed to thinking about classes. In C#, classes are static and have their requirements frozen quite early in the game – usually before runtime. In Ruby, a class is an intention. It’s a document, and it may not be complete yet until knowledge available at runtime is incorporated. And the requirements aren’t frozen early in the cycle.

    A class in C# has the skin of a soccer ball. A class in Ruby is a soap bubble.

    Of course a class in C# isn’t a soccer ball, and of course a class in Ruby isn’t a soap bubble, but think about the permeability of their objects this way. And realize that Ruby programmers don’t have to make this uncomfortable mental switch from the thick, impenetrable husk of C# objects to the accommodating cell membrane of a Ruby object. If you haven’t worked in an environment with husky objects, the very thought of it might seem a bit arbitrary. And in fact, it is arbitrary. It’s arbitrary to the kind of language that C# is.

    For a Ruby programmer, no other choice would make sense. Why give an object an impenetrable husk? It’s just an object for gosh sakes, not a tyrannical rule.

    Somehow, those Rails guys have not needed a dependency injection framework in order to build Rails. And somehow, they rock the web world. You can’t deny that there’s something going on here, but you can’t quite see how it could work… but it does, and it does it quite well AND quite maintainably. There must be other design principles in play – ones that may never be visible from C#. Maybe it’s just configuration DSL’s and hashes. In the end, it’s all raw Ruby.

    Think about “instructor” rather than “constructor”, and you’ve got yourself the beginnings of dependency configuration API’s and DSL’s in Ruby.

    If you really want to be old-school about dependency injection, create a class macro of the likes of:

    def Foo
    depends :bar
    end

    (don’t… I’m just kidding on that one)

    So many of the things you do in C# are protections against getting backed into a corner that has something to do with the sealed nature of static, class-oriented code. The holes we leave in the husks of C# classes – like constructor args – are escape clauses for otherwise impenetrable skin.

    Of course, the C# programmer in you is thinking, “But that’s good design! It documents what my dependencies are! It makes dependency code explicit!” Well, before you can decide on what is or isn’t explicit in Ruby, you’re going to need to go native for a while until you can see the forest for the trees. “Explicit” is another one of those things, it turns out, that is really culturally explicit.

    The only reason to feel that it’s natural and right to use constructor args and such is because it’s what you’re used to, and it’s the right thing to do in C#. Once you’re not constrained by C# laws of physics, all bets are off on what you can think of as “good design” or “bad design”. Until your mind works in Ruby, you’re going to be thinking in C# and speaking in this other language.

    That might make you bilingual, but it won’t make you bi-cultural. It’s when you become bicultural that you understand dependency configuration in Ruby, and understand that it’s usually not something that’s exiled to a “container”, but is in fact kept local to the classes that are being served served, and driven by plain old configuration API’s and DSL’s, and often by plain old code.

    It’s not elaborate, but then again, elaborateness is often an indicator of inelegance. And that’s not usually as productive as elegance.

  • http://www.tavaresstudios.com Chris Tavares

    So poor-man’s DI is an antipattern in C# and a container is the pattern. In Ruby a container is an antipattern and poor-man’s DI is the pattern. Am I getting the correct jist of your statement here?

  • Ryan Svihla
  • http://ampgt.com Scott Bellware

    Chris,

    No, you’re not really getting the gist because your characterizations are still from the perspective of C#.

    There is no “poor man’s DI” in Ruby. When speaking of the patterns from within a Ruby perspective, you’re not really speaking about them with one foot in Ruby and one foot out of Ruby. It’s not a poor man’s DI unless you do it in C#, and within that cultural context. Otherwise, it’s a comparison of apples and oranges while wearing orange-colored glasses that don’t let you see that those other things that appear to be colored orange aren’t oranges.

    There are so many subtleties in the ambient environment in Ruby that are also in-play that makes the analogy too unnatural to stick. For this to be poor man’s DI, you’d have to thin out Ruby until you’d only be left with the subset of compositions available to you in C#.

    It’s not like there are no registries in Ruby frameworks. Sometimes they’re a necessity – especially in the bowels of frameworks. Sometimes not.

    The ultimate issue here is that in C#, there’s a kind of foregone conclusion in the culture that suggests that dependencies should live and die in a remote container; that only dependency receptors are indicated in the classes that use them. Ultimately, this is an expediency that helps in a language like C#. It’s the right thing to do considering the limitations of the language. We’re amenable to believing that this is the way that software design is done across the board because it’s what we’re used to after years of working this way.

    In the end, and from the perspective of design elegance – meaning “simplicity and clarity” – moving the control of dependency creation to a remote location decreases what can be learned by reading the code under your nose.

    In C#, removing that knowledge to a container is usually the best way to do things in all situations, and we use registries in situations from the bowels of our frameworks to the outermost surfaces of our application code. We’ve even institutionalized the foregone conclusion that having dependency management right there in the object that uses the dependency is a violation of SRP. And this might even be a meaningful interpretation of SRP – but made from within a C# cultural and cognitive bubble.

    In Ruby, registries are useful when they’re useful, but where there’s an opportunity to use a more elegant pattern, then that option is open, and often than option is taken.

    Ultimately, moving the instructions that control the life of a dependency away from the depending object reduces what can be immediately known about that relationship by reading the code of the relationship. But in C#, it’s a fascinating exercise to move that control to some very impressive tools, but we don’t pay attention to mathematical elegance in C# as much as we do in Ruby culture. The culmination of all of the attention paid to elegance in Ruby – and that can be paid – accounts for a good bit of the higher productivity that is roundly reported by people who’ve taken on the responsibility to see for themselves what all the hype is about.

    When Roy reads this, he’ll quite possibly read a vindication for TypeMock, but it’s not a vindication for TypeMock. The reason is that the mechanisms supporting elegance in C# are far fewer than Ruby, and TypeMock can only deliver on a narrow subset and only in a narrow set of circumstances – namely: testing.

    In Ruby, the things that TypeMock brings only to testing permeate every kind of coding and therefore design. And the productivity you get from elegant design is a higher order than what you can get from narrowly-focused tools that mimic elegance.

    Your options in Ruby are far greater. In fact, they’re vast. And while it might seem that this gives developers too many options, it doesn’t. In fact, it gives them a broader mind and a broader perspective, and teaches them to make even sharper and more precise decisions, closing the productivity gap even further. The vast array of greater options inevitably creates a finer, more honed sense of design. You end up readily and directly seeing design qualities that are beyond the perceptive abilities of something more coarse like C#.

    And the things that DI brings only to object construction and lifetime management also permeate every kind of coding you do in Ruby. And they’re right there under your fingers; a part of the language that you can always leverage, rather than a tool that is inevitably an afterthought.

    You do what you have to do in C#, but in the end, we’re using tools to work around language limitations, and we’re not able to explore the rest of the design abilities that are the full potential available to us when we shed the limitations entirely.

    From what I can tell, not even the things that are on-deck for C# 5 bring the full potential of design options to bear. Anders keeps talking about compositional language developers not really wanting to lose strong typing and frozen code, and really just want what the C# team is calling “dynamic construction” (rather than full meta-programming). And ultimately, he’s talking from the perspective of a C# developer rather than, for example, a Ruby developer.

    I don’t miss intellisense and automated refactoring as much as I thought I would. Even though they’re damned convenient, I can’t afford to trade the productivity increases I get from Ruby and from Rails for the expediency of tooling that requires design options to be so truncated, and that require so much brute force to work around. We shouldn’t saddle ourselves with these burdens to begin with.

    If I were a Rubyist who had never worked with C#, I might look at C# with DI and conclude, “poor man’s composition”. But I’m not. I’m someone who has gone beyond tinkering, and I share the experience of others who have done the same. I share the opinion that the subtleties of design that you learn from not just the Ruby language, but the Ruby mind, are not available to C#.

    It ultimately comes down to “safety”. You don’t have any kind of forced safety without imposing some constraints on the full breadth of choices. But safety is also a matter of responsibility, and where you draw the line will dictate what you can be exposed to, and therefore the extent of what you can learn. You can’t learn Ruby from C#. It’s like trying to learn about your country from within the bounds of your state.

    No matter how many workarounds are bolted on to C# to approach the capabilities of a compositional language, it will never be a compositional language. The availability of capabilities will be fragmented and uneven – like TypeMock providing similar syntax only to testing, and DI providing dependency composition at the cost of elegance. When these capabilities are distributed evenly throughout the code and coding, new kinds of leverage become available that go beyond mere constructor interception.

    I can provide some thinly-veiled appearances appearances of compositional coding in C# by using poor man’s dependency injection and test-time static interception using the CLR profiler API, but that’s all I can do. I never get the rest of the capabilities that become apparent when I’m not limited to using these techniques in such a narrow band of situations and circumstances.

    Which leads me to this conclusion about C# (that may very well infuriate anyone who has their entire career identity wrapped up in a single programming language, and the fear that it might lose any of its prevalence): The reason why we have such ideas as “poor man’s DI” in C# is because C# is poor man’s OO.

    And inevitably, the learning trajectory that points to the rest of the productivity available to software development points out of the C# sphere.

  • http://www.lostechies.com/members/chadmyers/default.aspx chadmyers

    @scott:

    Singleton is one form of DI, but it’s particularly pernicious one in C# due to static-ness. But in Ruby, with open types, it’s not pernicious and therefore not a big deal, right?

    I realize your example was addressing a single point, but if I may stretch it a little further just to understand strengths/weaknesses, if you needed different forms of _baz_ depending on the situation, then the Singleton approach might not be good and you’d switch to a different approach.

    Back to C#, since C#’s good/acceptable modes of DI are limited due to static-ness, an IoC container becomes a must for any sufficiently large set of dependencies. The container necessarily becomes the point of swapping in different dependencies (i.e. different impls of Baz) due to context.

    Back to Ruby, but since Ruby doesn’t have the constraints placed on its modes of DI, it becomes easier to swap alternate implementations based on context and so a container is not necessary. Or perhaps you might end up having some of the features of a container (conventional wiring up of dependencies, for example), but they wouldn’t be in the form of a container, they’d take various other forms.

    The constraint in C# of having one or two good modes of DI necessarily forces all those features (plus a bunch of others that would be unnecessary in Ruby) into a nexus or “IoC Container”.

  • http://ampgt.com Scott Bellware

    Chad,

    I wouldn’t call a Singleton a form of DI as much as something as a problem in a pre-compiled language that DI work around.

    The rest of what you said is reasonable enough.

    Although, there’s an interesting gem in what you said that is an awesome example of the difference between C# thinking and Ruby thinking:

    If I need to swap different kinds of Baz subclass, I’m going to need a mechanism for that. But there’s nothing that says that I absolutely must solve this kind of problem with different implementations of Baz subclasses.

    Since I have a mechanism for putting the right Baz in the right place at the right time, I might have that mechanism compose an implementation of Baz (or whatever, the class isn’t relevant since there’s no strong typing – it could be an instance of Object) from smaller capabilities.

    If it’s different implementations that are needed, then representing those implementations with different classes isn’t a foregone conclusion. If it’s an example that’s well served by class abstractions, then great. If not, module abstractions and dynamic mixins (Object#extend) might be a better fit. Or maybe meta programming might be the right answer. Or maybe method_missing.

    I’m not saying that classes aren’t the right solution, but the might not always be the best solution.

  • http://thatotherguy.lostechies.com Greg Long

    @Scott
    You wrote: ‘In Ruby, a class is an intention.’
    This really stuck with me because it is similar to my recent way of thinking (in C# though). I’ve become drawn to an idea of difference between objects (things or nouns that possess state) and what I’ve been thinking of as behaviors (or, as you put it – intentions). Ultimately they may both be represented in my code as c# ‘objects’ but I’ve been finding a separation of the two – at least mentally and often physically – more natural to me. I’m not certain where this will lead yet in C# because I haven’t worked through all the implications yet. For now, it means my interfaces have shrunk considerably and only contain method signatures because I don’t see them as ‘Interfaces’ anymore but as behavioral ‘agreements’ or stated intentions. This has really changed how I look at an application and I really like results of this idea. I’m not necessarily excluding state from my objects or even avoiding it – but as much as possible I’m letting the behavior or intention of an object be fluidly contained within the boundaries of it’s stated behaviors (intentions, or in C# the interface(s)).

    Is this close to what you meant? Could you elaborate a bit for me please?
    Anyone – Is there a non-trivial example or code-base I could read to better demonstrate this in Ruby?

  • http://ampgt.com Scott Bellware

    Greg,

    What I meant by a Ruby class being an intention doesn’t really point to intention-revealing design, which seems to be the design quality that you’ve been recognizing in your work. Although once you’ve seen intention-revealing design in your work, you’ll pursue it in whatever language you use.

    Saying that a Ruby class is an intention is a reflection of how the capabilities of a Ruby class aren’t entirely reflected by a class’s code in the editor. What you see in the editor is a hint of what the class’s capabilities might be.

    So, to disambiguate from Intention-Revealing Interfaces that is already a well-known quality, let me change my statement to: In Ruby, a class is a hint.

    In C#, a class’s capabilities are frozen in the editor (really, the compiler, but it’s not a significant difference to programmer workflow). But the time a C# class gets to the compiler, it’s capabilities are frozen. We can do a number for things to work around that imposition, but it usually requires a tool that re-implements some of the capabilities of the C# compiler.

    A Ruby class documents the intention of what a class will do, but it isn’t limited to what’s in the editor. The rest of what a Ruby class can do is differed to runtime. A Ruby class may remain intentionally-incomplete in the editor, knowing that the rest of its capabilities will be added at runtime based on how the class will be used in the myriad of situations it will be used.

    We have some tools to do the same in C#, but the ease and accessibility of them doesn’t approach Ruby because the capabilities are part of the Ruby language rather than aftermarket tools that work to undo C#’s strictness. This ease and accessibility accounts for some of Ruby’s productivity increase over C#.

    We create, maintain, and use aftermarket tools to work around the limitations in C# that are cause by the strictness of “safety” protections that were added to C#. Limitations were added to C#, and we add further workarounds to loosen those limitations. In Ruby, the limitations weren’t added to begin with, so we don’t have to add anything further to get the essential experience that we’re after in the first place. Because we add further tools to loosen strictness in C#, we’ve had to choose which areas of strictness to loosen. We can’t address all of the strictness in C# and so we remain subject to the limitations – no matter how hard we try to undo with aftermarket tools what has been embedded into the very foundation of C#.

    Adding further tools gives us a chance to workaround limitations, but it does so at the cost of design elegance. That design elegance is the generator of higher order productivity. Design elegance can’t be achieved as an afterthought. Any time a remediation is added to a solution to solve a problem that we shouldn’t have to begin with, complexity is added which puts a limit on how much elegance can be achieved. Only when the limitation is removed completely (rather than worked around) does elegance come back into reach.

    So, while it’s definitely vital to have intention-revealing interfaces, that is only part of what categorizes the mathematical elegance that is at the heart of greater productivity.

  • Steve

    To echo what Greg asked, is there a non-trivial example out there to look at? A link to github would suffice.

  • http://ampgt.com Scott Bellware

    Steve,

    What is it specifically that you want an example of?

    I’m asking because some things can be exemplified in materials (code, etc) and some things can be exemplified in experiences (doing, practicing, learning, realizing).

    If what you’re looking for can be exemplified in material, I’ll do my best to point you to it. But if it’s something that can be exemplified in experiences, I hope that you won’t be put off if I say that you can only see it through the lens of your own breakthroughs – just as Greg has with a growing awareness of intention-revealing interfaces.

  • Roco

    I’d like to echo the requests for seeing some code. All of this is very interesting, but some times too much armchair philosophy leads to confusion for Ruby newbies like myself.

    How about something like, “Here is an example of a common task as it would be implemented in C# using interfaces, IoC container, i.e. standard C# practices, and now here it is in Ruby.”

    It can be a trivial example, just something that highlights all of the topics that have been touched on at length in recent posts/comments.

    As a Ruby newbie, I would really appreciate it.

  • Steve

    Scott,

    I think Roco hit the nail on the head there. I don’t even need the C# version for the code, although someone writing a blog post showing both would be fantastic.

    I’m sold that Ruby is “better”, I’m sold that having a framework with testing/DI baked in is “better”, now I just need to see some good examples of it, and unfortunately, they’re not that easy to find.

  • Steve

    I worded that poorly. There are plenty of good sites to go look at Ruby code, but it seems that so much isn’t in the “Ruby Way” (i.e. Tests are rarely shown, etc.)

    I’d love to see a github repository of a Rails (or Sinatra app) that is coded the “Ruby Way” with complete tests, exception handling, etc. that I could use as a nice guide.

  • http://ampgt.com Scott Bellware

    Roco and Steve,

    I want to reiterate, as I have for many years, that material serves one level of learning – the beginning, and that experience serves everything that comes after the beginning. Far from being armchair philosophy, it’s something that is observed by people who make transitions from the basics of practices, to intuitive mastery of practices.

    Unless you’ve realized this for yourself, you will continue to have every confidence that what you know about learning is true of all of learning.

    I’m not holding anything back. I spend one hell of a lot of time teaching face-to-face because I know that material learning just doesn’t cut it. In fact, all it can do is get you started.

    I know that you want to see point for point comparisons of C# to Ruby. I know that point for point comparisons don’t do much more than reinforce the one-sided understandings that we already have.

    I understand that this is a frustrating answer, but it’s the real answer, and it’s an answer that will be given to you by anyone who has experienced the breakthroughs, a-ha moments, and epiphanies of learning, and more difficultly, the realizations of un-learning.

    As a more practical matter, I personally can’t afford to invest in building such materials, And because my experience in both learning and teaching has shown me that these things don’t really bridge the gap as we think they might from the outside, I’m reticent to invest in that kind of material. It’s not the kind of teaching I do, and I’ve never seen anyone do it effectively, and do it without creating yet more misunderstanding.

    The learning return on that kind of teaching investment is too little for me to invest into it as a teacher – no matter how much you believe you’ll learn from it. I’m not saying this as an armchair philosopher, I’m saying it as an experienced philosopher – in a very literal sense of “philosophy”.

    Here’s what you can do right now that will indeed clear up all of this lack of understanding: build an application on Rails. Or better yet, build a business on an application built on Rails. While you’re doing it, keep an eye out for difficulties that you feel would be solved with dependency injection. I think you’ll find vastly fewer of them than you might expect. In the mean time, you’ll have built an app and maybe even a business. And in the process, you’ll have undertaken experiences in learning, and more importantly, in un-learning; in recognizing unconscious biases that direct our ability to learn.

    So, you could require me invest in creating a curriculum of material to demonstrate something that I’m very confident won’t have a profound effect, or you could make an investment in understanding on your own by installing Rails, watching some screen casts, reading a book (or three), and using practice and experience to shake loose the un-learning that does create realization.

    If you believe that it’s my responsibility to spoon feed any petitioner to greater understanding, then I’ve failed to clarify my position on this kind of learning and teaching over the past five or six years.

    Nonetheless, and with great sympathy for your predicament, I’ll offer this: I can’t show you a point-for-point comparison between C# using interfaces and dependency injection and Ruby. These are structural design issues, and they can be very different in either language. And where they’re similar, they’re only profanely similar; the powerful pervasive subtle differences aren’t revealed. They’re revealed through practice.

    But a little bit of indulgence nonetheless…

    At a very high level though, there are no interface types in Ruby, so there would be no interfaces types. And there’s very little need for an object container in Ruby, so there’d be no dependency injection framework as per what “dependency injection framework” means in C#.

    That said, if you’re writing a framework, you’re going to come across dependency management issues. But if the first thing you do in Ruby is invest your C# biases in a new framework in a language that you don’t have fluency with yet, you’re probably letting yourself get ahead of yourself.

    And if you’re writing application code within a framework context like Rails, you’re extremely unlikely to need a dependency injection framework and an object container.

    What will you use other than static dependency injection? Non-static dependencies – because all dependencies in Ruby are non-static. What’s in the code is just a “hint”. You’ll use object constructors, and Singleton patterns. At a more advanced level, when creating plugins and frameworks, you might add lazy evaluation patterns and configuration patterns.

    Specifically, take any C# code that isn’t framework code, remove the interfaces and remove the dependency injection. Replace the dependency injection with calls to constructors (also called “initializers” in Ruby) and Singleton patterns.

    At that point, you’ll have the material in our hands that is a beginning to a comparison between C# and Ruby. Heck, you could do this in C# to see what the Ruby might look like, but it still won’t be too terribly representative, and that’s because you can’t represent Ruby thinking with C# thinking, no more than you can represent C# thinking with UML thinking.

    To get Ruby, do Ruby. To overcome C# bias enough to get Ruby, do Rails. To get Rails, do something real with it. I’ll eat my hat, your hat, and the collective hats of the entire community if you don’t come back later and corroborate everything I’ve said here – even the stuff that you believe is armchair philosophy.

    I’m not trying to be evasive here. I want you to know as much as you need to get an understanding. But I am saying that this kind of understanding is had through experience, and in this case, it’s not experience, that is difficult to get your hands on. It’s not esoteric, it’s just presently obscured.

  • Roco

    Scott -

    Thank you for taking the time to respond. I am already on the path to learning Ruby and at the same time “unlearning” my C# habits at the same time.

    Still, I would like to see a little bit of code. Not an enterprise app, but something very small. For example, some class that takes an IRepository or ISomeService to coordinate and do some work. In C# we may only have one implementation of these interfaces but use these abstractions to promote good design and testability. What does the Ruby version look like? Do we just new them up in the ctor with default implementations as you may be hinting at?

  • http://ampgt.com Scott Bellware

    Roco,

    In Rails apps, for example, there’s no corollary to a repository class. It’s not really needed, and the Rails community never got involved in using Domain-Driven Design that way.

    So, this kind of comparison, as I mentioned earlier, isn’t one that can be made point-for-point.

    Nonetheless, let’s say that you’re using something like Sequel in Ruby rather than ActiveRecord, and if you’re doing class-oriented programming exclusively, then you might indeed have something like a repository.

    So, if I had a controller class that made use of a repository class, the controller code would likely instantiate the repository by calling its contsructor, or would get an existing the repository instance from some kind of Singleton pattern implementation.

    There’s not much to show here beyond SomeRepository.new – unless of course you’re writing a framework. But like I said, writing a framework at this stage of learning might be a very bad idea.

    The comparisons break down because the design patterns can be quite different, and desing can be modularized quite differently to reflect the capabilities of the raw materials of the design. The primary raw material is the language you’re using.

    Specifically to your question, yes, you “new them up in the ctor”. But be wary of what you presume about “default implementations”, because this is part of an unrecognized bias of working in a pre-compiled class-oriented language.

    The only time you have a default implementation in Ruby is when you choose to.

    With C#, what you see in the editor is what you get. It’s all default implementations – all the way down to the turtles.

    Even an implementation of an interface type – even though you might not see it as a default implementation – is indeed a default implementation. It’s just a replaceable implementation – but only at a class level. The class itself always defaults to the one and only implementation that it has.

    If you want a default implementation to be anything different in C#, you’ve gotta irradiate the turtles in an attempt to re-write their genetic code so that they’ll carry your default implementations differently.

  • Roco

    Scott,

    That makes sense. During my initial explorations of Rails I instantly noticed how they stepped away from some of the DDD hallmarks in favor of a more simple approach. The models are aware of their persistence to an extent, which was hard for me to deal with at first. Regardless, in hindsight my repository example was stupid as it doesn’t really apply here ;)

    I guess what I am struggling with, is how can I train myself to stop thinking in terms of defining behavior in the form of an interface or abstract class construct that is essentially “fixed”, and instead do it the ruby way. More specifically, how do I replace the interface/ class dependency approach with a more dynamic approach using things like code blocks in Ruby? It still eludes me.

  • http://ampgt.com Scott Bellware

    Roco,

    I wouldn’t start with trying to replace classes with callable objects like blocks, procs, or lambdas. There are classes in Ruby and OO is still a perfectly good way to represent abstractions. I don’t avoid using classes, in fact, I use them more often then other kinds of representations. But I also use modules, and there are a whole other set of ideas that go along with modeling compositions with modules, and with dealing with the particularities of modules.

    The only way to practice not thinking in terms of interface types, or not thinking n terms of types at all, is to force yourself to not think in those terms. If you pick at it, it will just continue to itch. Just stop thinking that way until it becomes natural.

    Everyone experiences the panic of not doing things with interfaces and abstract types. You just have to take the step knowing that there’s going to be ground under your feet and there’s no fall waiting for you.

    The challenge with using ActiveRecord models, frankly, is often more cultural that technological. Moving away from the DDD patterns to ActiveRecord initially feels like taking a step backward in what “proper” design should be, but it’s that drive for “properness” or “purity” that drives a lot of people to get caught up in the DDD orthodoxy without understanding why.

    It’s a bit cold, but there’s really only one thing you can do: get over it. It is, in fact, something to get over. If I were working in .NET, though, I’d still create modules for persistence that are separate from model logic. That’s because .NET dependencies are static dependencies and this constraint means pre-formulating strict separation before hand.

    If you used the Active Record pattern in .NET, it would likely lead to less overall simplicity as a measure of simplicity for the whole effort and the whole system, while in Ruby, the absence of static dependencies allows systemic simplicity to be sustained.

    Ultimately, it’s a cognitive pattern that has to be overcome; what I called “un-learning”. It’s much harder to un-learn than to learn. Adding new habits to a blank slate is more work that moving existing habits aside while also doing the work to form new habits.

    Ultimately, if everything could be learned without the formation of attachments like habits, it would all be a lot easier. But in the face of habitual patterns, the only thing to do is recognize their presence, and move on despite all of their protests about how “unnatural” these new patterns are.

    That’s why I think it’s so much easier to start at Rails. At least with Rails, you don’t have to start from scratch, and your code can largely be held in an outer structure that lets you start with the basics of plain old class-oriented development that you already know.

    One more thing about Rails, though: there’s no need for those Domain Service patterns in Rails. All of that code belongs in the model objects. And that can be one hell of a hurdle for .NET developers with the DDD pattern language bug – maybe even harder to accept that ActiveRecord in some cases. Nonetheless, it’s an exercise you have to undertake to make the transition.

    The one advantage you already have over many Rails developers is that Rails developers often believe that the only archetypes in a Rails app are models, views, and controllers. Many Rails devs suffer from their own orthodoxy that leads to the unquestioned belief that all classes with code are model objects.

    You already know that there’s more to a MVC app than models, views, and controllers. What you might not already know is that there are far fewer of those other classes than you likely need. But working in Rails and in the Rails ecosystem will show you all these things, and you’ll have to temper what you hear with your own experience, and you’ll have to temper your own habits. It’s a fine balancing act, and you’ll inevitably fall back to C# habits. Just question them and become more aware of them. One day, you might even have legitimate questions about the Rails way, once you get a firm grip on on the subtleties.

  • Roco

    Scott,

    That really helped clarify a few things for me. Thanks again.

    I will continue on with Rails first. At least that gives me some established structure to work with as I learn the ropes.