February 11, 2015

Why: adverb; for what reason or purpose. 

It may come as a surprise to some of you that I'm not an Automata. Surprise! I'm a human being. Unlike a robot or even a cyborg, I can't instantaneously learn Kung-Fu by downloading it. It takes time to accumulate knowledge and experience. I have to read, try and sometimes fail before I learn about something but eventually with persistence, I get there. 

For those readers who are not human, this process of learning begins with why. The pursuit of why something happens is what leads to understanding, not the other way around. I often find the why conspicuously absent from technical articles, which focus solely on the how. Not that there's anything wrong with that, mind you. Sometimes that's really all that's needed but other times, what usually starts as a journey, can end up becoming a mission. Searching, scrounging and sifting until, hopefully, I understand why.

Dependency Injection (DI) and Inversion of Control (IOC)

I'll admit, I had no practical understanding of the terms. I heard them mostly through a bluster of buzzword salads which I find unappetizing. (I'm wordy but it's a means, not an end) This time though it came up recently several times so I curiously began querying for answers. Sure enough, High Priests are already condemning it's lack of ubiquity so I felt as though I MUST be missing something big. I was sure it was some sophisticated strategy, tantalizing technology or epistemological epiphany. Why else would it be held in such reverence, such obfuscation, such... prolixity?  

Dependency Injection(Wikipedia): is a software design pattern that implements inversion of control for software libraries, where the caller delegates to an external framework the control flow of discovering and importing a service or software module.

Wow. Yeah. Ok. Sure. Wait, what? Reading this is taxing. Like I mentioned previously, I'm not a machine so I have no interface for language this obtuse. It's like being asked for the time and responding: "The 4th dimension is exactly 33/60 through 18/24 of a rotation of the earth on it's axis." Accurate only technically but borderline gibberish. Certainly of no help to anyone looking to understand this seemingly inexplicable topic. 

After finally finding a thoughtful explanation, (most were so vapid as to leave me more confused) I was at first a little doubtful what I read was the answer. Why was there so much ado about using interfaces? It's one of the core components of all object oriented languages. Surely there isn't a design pattern SIMPLY TO TELL YOU TO USE AN INTERFACE! But sure enough there is. It's worth mentioning that with the paucity of boundaries given in most articles, one would be left thinking that you should be replacing every class reference with an interface. EVERYWHERE! Just go out and double the size of every library with interfaces. No limit. Why? Because, you imbecile! Dependency Injection! (face palm) 

Absolutism is a poor, poor practice which leads to poor outcomes. I certainly don't know everything but I do know one thing: when to use an interface. Perhaps it's time to explain a bit about... what's the word.... damn... uhh.... oh right; WHY! So here's my take:

If you use interface types as method or constructor parameters, those parameters can be swapped out with any implementing object available in any given situation. If you ever even knew why interfaces existed, you probably already understand the basics of this concept but if you don't, no worries. Living is learning. Let's forge on with an illustration using a good 'ol car analogy. If you were to design a car with wheels permanently fixed to the car, you'd be buying a new car every time you get a flat tire. However, if you design a car to work with a standard wheel interface (four or five lug nuts), then you'll be able to swap them out with snow tires, rain tires, 50" rims or whatever your heart desires. The point isn't to "have a caller delegate to an external...." or other vague rhetoric intending to sound smart (sigh). The POINT... is to make a modular framework that is flexible and reusable.  

Interfaces describe the minimum requirements to be functional. If your class provides this functionality (known as implementing the interface), it'll fit right in. But again. If you were only shown how to use an interface, you might miss the forest for the trees. Knowing why will help you understand that you don't need to replace every class reference with an interface. You'd infer that you only need to consider replaceable parts. Again with the car analogy: If you damage the frame of a car, you're not going to find after-market parts for a frame. It's simply not a replaceable part. Making it replaceable makes NO sense. But again, not everything is a car. Heck I've even written a class library almost entirely consisting of interfaces! So use your best judgement. 

Test Driven Development (TDD)

So if you ask around, it's all the rage to be practicing Test Driven DevelopmentTM. Everything is better with Test Driven DevelopmentTM. It's so easy to start Test Driven DevelopmentTM. Test Driven DevelopmentTM saves lives. Test Driven DevelopmentTM cures blindness. Test Driven DevelopmentTM can even make you popular! You're not already using Test Driven DevelopmentTM? What's wrong with you?!?! Oh right, repeating something tirelessly, breathlessly doesn't help you understand why you should do something. 

So consider if you will, the lifecycle of designing software. Testing what you've built should at least cross your mind. Once you've been burned badly enough by maintaining untested or manually tested code, you'll probably want to seriously consider automating your testing. Then once you begin automating your testing, you'll find it easier to incorporate testing into the design from the beginning. Voila! Test Driven Development is born. It's more than just an obnoxious phrase used to bludgeon any and all conversations into a stalemate. It's actually helpful.

So now that we know why, what does this have to do with DI and IOC? Well, to effectively manage testing any code, you'll need to isolate the core of your code from the implementation. In a web application, the core is generally found in the libraries. The implementation is generally in the sublayouts, web services and other end points. In a unit test however, the end points are irrelevant. You can, and I do, test end points with web tests, but I really want to focus on the unit testing here. To be able to run your code outside of a live environment means you'll have to replace situational content from databases and web services with static, testable components. To do so, you'll need to make these inputs provided as... wait for it... interfaces.

Wow. Full circle right there. Development begets testing. Testing begets interfaces. Interfaces begets modularity and apparently it's very own design pattern (shrug).

Okay, so one last thing about testing because, I've been hearing conflicting opinions on what you should focus on when testing. In my, albeit limited, experience, I've come to align myself with the mindset that tests can serve both as checks on your system and as documentation. In this way of thinking, if it in anyway shows the next guy(or gal) how to instantiate and use your code, it's helpful. Most importantly though, testing is about stability. If it helps you maintain a stable code base, do it. I'd rather have too many tests than not enough.  

A Few Minutes with Andy Rooney Mark Stiles

Alright, I'm almost off my soapbox. Here's where if you didn't get the sarcasm and insinuations, I spell it out for you. If we never learn to question why we do things, it's no longer a science, it's a religion. There's no nuance, only "The one true way". What's the answer to the unique problem you're faced with? Apply approved patterns. Don't think, just do. To be sure, there are plenty of optimal approaches for certain types of problems but I'd rather know why things work or don't so that in the event my situation is unique, which it ALWAYS is, I know how to adapt what I've learned. I'm not a compilation of things I've memorized. I'm a human being, not a robot doing. So don't be afraid or discouraged to try something new or fail. Encourage exploration, collaboration and most of all, discussion.