Techie time. :-)
I did try to write this for the non-technical audience, but it was getting a bit convoluted and my point was a long way off, and I feared it was going to be diluted. So this is a bit techie. Sorry. :-)
The SOLID design model is a really good template for building systems. Each object, and component, has a single purpose. Components can have additional features, but objects should be responsible for one task. Not reaching into someone's code to change it because you need to is also a good idea. Changing the actual code, if you have access to the source code is okay, but changing a function or a method is frowned on. Mostly because it makes your code very tightly coupled to the bit you're changing. If the manufacturer of a milling machine, for instance, changes how they run the cutting head, and you've taken over the bit that does that - you're screwed and maybe the operator of the machine is, too. And so on. Basically, loose coupling and wiring things together is the way to go.
For instance, I can replace my television's controller with a better one; the cables plug in and that's that. The cat can use the old controller as a neat place to sleep (don't ask why, she just likes sleeping on it) and I can watch the telly. The two devices - the screen and the controller - are loosely coupled. I don't have to change the screen to use a new controller, and I don't have to change the controller if I buy a new screen.
Okay... The Ruby language community seems to reject these ideas. And the reason they reject them is arbitrary: it seems they are rejected because the ideas come from statically-typed languages.
That, in a nutshell, is the overall impression I have from reading blog posts about the topic. (To be fair, the only one that is given time of day is the idea that classes should encapsulate a single responsibility.) If you adhered to the general rejections of the Ruby community, you couldn't possibly come up with an alternative to Spring, for instance. Which means the infrastructure (the coding practices, the available code and so on) eventually becomes closed off. You *can* come up with an alternative to the XML-based wiring of Spring, but only if you break a few conventions that all begin with "we don't need that feature from" <insert language being criticized here>. The point is then demonstrated with an example of why such-and-such isn't needed.
Part of this is cultural, and it's encouraged by that wondrous tool, GitHub. If you can easily fork a component, you don't need to adhere to the SOLID model. PHP, for instance, has a practice of "don't touch the insides" of an imported component. Because Ruby is so dynamic, it seems to be generally not even considered not to do that, unless the component is a Gem. The same reasoning is applied to interfaces and abstract classes; the general idea is "you don't need it". Which could be a good thing if someone could show why they're not needed. So far, after some extensive Googling, I haven't seen a single persuasive argument. What I have seen is something I see in political communities: agreement based on pre-existing perceptions and prejudices.
The thing is, the Ruby community argues more for a business process than it does for a technical practice. Testing is all well and good, but if your tests aren't any good, or are missing an important part of what they should be testing, your business process just failed. As did your argument that testing will catch all the problems. This is ably demonstrated by the fact that statically typed languages also have (some excellent) test suites.
Another argument against abstract interfaces and classes seems to revolve around the source code. Essentially: if you have the source code, you can read it and see what's what. And with Ruby you almost always either have the source or can get it. I don't know what to make of this argument. It is, quite frankly, silly. I have the source code to PHP and ObjectiveC interfaces; that doesn't mean I'm going to change it them to accommodate my use case. Not unless that's really necessary! A reasonably well-designed interface exists for a purpose. It defines what you have to implement. A well designed abstract class saves a lot of bother; it allows you to implement methods for your use case and ignore the rest of it. Sure, you can emulate this with concrete classes and inheritance - but the reason a new model was derived should indicate something about the failings of this! (Basically, you shouldn't be able to instantiate a class that provides "most" of the functionality you need; you should separate the common methods from the concrete implementation because it makes it much easier to test and maintain the two different abstractions. Also, I can supply an abstract class, leaving you to implement the concrete. And we don't have to be on the same team!)
All in all, Ruby lets you do things and that's taken as a justification for doing them. It's not that the ideas behind those features are bad, but sometimes using them is a Really Bad Idea. And rejecting practices simply because they are from other programming paradigms is a Really Silly Thing To Do. Relying on a business process - testing - and hoping that the other guy can read your code isn't a clever way of building systems. All you end up with is tightly-coupled systems where version control assumes an outsized importance. I don't know about you, but I prefer to think about interesting problems and not spend hours finding out that I should have used that particular version of a component because the guy who wrote it changed the bit you've hooked onto in the next version.
And now to try and figure out how to do what I need to in Ruby. :-)
Carolyn Ann
0 comments:
Post a Comment
Anonymous comments are disallowed for the time being.
Comments that are melancholic and miserable are discouraged; self-pitying whining is also discouraged. Gender Reality exists for, and welcomes, that sort of sniveling.