Black box development

In ruby, and several other languages, there are a few philosophies you can follow. No, I'm not talking about things such as KISS or POLA or anything else along those lines. I'm talking coding methodologies, guides and mantras to how you should write, test, and document your code.

I've dabbled with TDD, or test-driven development, BDD (behavioral driven development), and other similar philosophies, and have found them all to be lacking in one area. So I've decided to take it on myself to start drafting a new one. I am not as smart or experienced as other developers, but hope that my insight into this resonates with some people.

Shortcomings of existing methodologies

The current programming methodologies are fine and good, and suit a great number of people very well. However, there is always a room for improvement, areas that these systems leave raw or rough, sore spots that need an ointment.

Test Driven Development

TDD's first and foremost goal is the writing of good tests. It states that you should write your tests first, watch them fail, then write the code to make them pass. This is a good philosophy, as it ensures code is well tested, but has the nasty effect that devs spend hours writing increasingly complex tests for edge cases, and then, fatigued, churn out sub-optimal code. Furthermore, most devs who embraced this camp have completely disregarded proper documentation. I've heard, from some devs, that “the tests are the documentation.” This is utterly and completely backwards. Tests are to test behavior, not to document your code. They are often difficult to read, even with “helpful” tools like rspec, and rarely are more enlightening than the source code itself.

Behavior Driven Development

This is an offshoot from TDD, and aims to solve a few of the problems of TDD. It also has the lofty goal of bringing management onto the factory floor, and have them write the tests. This is very much a pipe dream, and seems to just cause developers more trouble. While BDD tests, such as those using Cucumber, are somewhat easier to read than traditional testing tools, they are still tests, and still don't provide adequate documentation.

Testing is overrated

This is another camp that is all too common, and I've even fallen into its methodologies before. Its a very tempting philosophy, typically driven by the fatigued developer, who just wants to go home at the end of a long day. The idea is that if things in your script/app break, then you can investigate and fix them as they crop up, and that your future time is less important than your present time. In some cases this may be true, but it always leaves me with a bad feeling in my stomach. I don't need 100 bugs popping up right after a massive deploy, and would probably curse the dev who didn't weed them out in the first place, usually myself.

Just write code, forget everything else

Similar to “Testing is Overrated,” this is an even more baffling group. Its idea is that you shouldn't waste time with comments, tests, documentation, or any of those other frills. You should just write clean, clear, and understandable code, and spend the time you'd “waste” on the frills in bettering your code. While this is amiable, as so much code out there is a horrific mess, its unrealistic. Everyone cuts corners at one point, and if you spend time on a particularly nasty problem, its nice to leave a comment or documentation stating what you did and why, so that future developers (probably you) won't hit the same pitfalls again.

A new methodology

Or, more accurately, a fusion of the above into a coherent whole. Each system has good and bad parts. TDD ensures well-tested code, BDD ensures that we don't test implementation, but rather outcome, “Testing is overrated” is fast (at first), and “Just write the code” ensures that we stick to clean, readable code. Ideally, we should be able to merge these methodologies, throwing away bad and keeping good, much like what Matz did with existing programming languages when he was creating ruby.

The new methodology I propose is as follow:

Documentation first

Documentation serves as a design document, setting goals and desires for each method, and also as documentation (who would have guessed). It can incorporate the amiable goals of both TDD and BDD that we define what we want out code to do first, and then code it to match that, and may also help realize BDDs dream of having managers help developers. Managers often hand developers a design document of some sorts, which outlines what they want the code to do. So it isn't a stretch to think they could help write documentation.

Code next

This may seem backwards, particularly to TDD fans, but allow me to explain myself. We have a design document and documentation, from step 1, that define what we want our code to do and how we want it to behave. We are now ready to write some code, and reference our documentation as we write it (assuming we used some inline form of documentation such as YARD).

We write the code fairly early in the process, so as to avoid developer fatigue, ensuring the code is as clean and efficient as possible. In pair-programming environments, you could have one person write the documentation and the other write the code, as is commonly done with tests. Any implementation details should be documented inline via comments, so someone viewing the source knows how things work. This is not a call for hyper-verbose commenting, use your best judgment.

Test

Finally, now that we have some working code and documentation, we can move onto testing. But I'm going to place a constraint on testing. You are not allowed to read the source code of the method you are testing. At all. You may only reference the documentation you wrote in step 1.

Why? Because this lets you test the behavior of your code, without getting bogged down in implementation. It shows you your code the way an outsider who doesn't want to, or doesn't have time to, dig through the source code. It is in this step that you will most likely find the flaws of your documentation, and possibly even your code.

By putting tests last, we ensure that both our documentation and our code is tested, and accurately reflects what is going on within the code.

Refine

Always an important step, moreso over the life of the code, rather than its inception. As you add, change, and remove bits of code, you should follow the process with each modification. Update the documentation first, then update the implementation, and then the tests.

Black-box development

For lack of a better name, I'm calling this black box development. By treating the code as a black box, we are ensuring that we only test behavior, and the only way we know about the behavior is documentation. All we have to guide us is the documentation of what this is supposed to do, we have to take it on good faith that the documentation is accurate. Since we only test what comes out of the black box, we can ensure the machine functions, from an outside observers perspective, the same all the time, regardless of what happens under the hood.

Everyone knows what a car does. It takes people and goods places, quickly. Very few people, however, can accurately describe the internal processes of a car. And cars work in all sorts of different manners. Some (most) use fuel injection, others don't. Some run on Diesel, others run on unleaded gasoline, and still others use other energy sources. Some have 6 cylinder engines, some have 8, some have more or less. But all preform the same on the outside. That is the goal with Black-box development. Allow someone who has never seen your code to operate and use it, similar to how someone who has never driven a Camry can quickly become accustomed to one.

Feedback

Any and all feedback is welcome. You can comment on this article on one of the reddit postings (I'll read em both), or on my Google+ posting.