DEV Community

Discussion on: The assembly line, code, and Big O.

Collapse
 
codemouse92 profile image
Jason C. McDonald • Edited

I can appreciate that.

Of course, whether we should do one thing at a time or multiple things at a time also depends on the nature of the program. One change may necessitate seven others, two of which have to be done concurrently to avoid breaking the software. And then you have the complexity of multiple people working on the code at the same time; one person can be adding feature A, and another adding feature B, and a third fixing bug X. They don't think they're working in the same area (or maybe they do), but they wind up slamming into each other because A needs C and B needs D (which is incompatible with C) and the fix for X blocks both C and D.

Software is messy. :P

But yes, all that aside, I agree that we should (as much as possible) focus on doing one thing right instead of eighteen things half-right.

Now, there is a time when a code base can become TOO DRY (and DRY spaghetti is still spaghetti). Just take a look at the source for libstdc++ (compare and contrast it with LLVM's libc++.)

If we try to make our code too modular, or modularize it too early, it can become harder to maintain, feature-bloat quickly, and take until doomsday to release.

Let's take, for example, my C++ testing library, Goldilocks (part of PawLIB). I wrote it with some interfacing functions, but I hardcoded the shell for it in another application that was using Goldilocks. I needed it functional quickly, so that was NOT the time to build the robust shell.

Then, last week, I knew I needed to set up another project to use Goldilocks as well. Instead of C/Ping the hardcoded shell, I moved that into PawLIB proper, and added some abstraction. I got it functioning well...which, as I think you pointed out, is priority one.

Next, I realized I wanted to simplify the Goldilocks shell commands. While I was at it, I wanted to cut down on repetition, so I moved some common argument validation code into a separate function, and wrote a function for each major shell command. It worked, yay, moving on.

My eventual goal is to actually abstract to the level of writing Blueshell, which will allow an end-developer to just specify the commands, their argument data, and their function callbacks within a Blueshell instance; the shell is automatically created, with all the features you'd expect. That is a level of abstraction a ways down the road, as it will take quite a bit of work to achieve. I'm not there yet, but GoldilocksShell has moved me a few inches closer. I just add one abstraction and feature at a time, until I achieve that eventual modular structure.

So, that's kinda what you're describing, in my mind, but there's an important lesson to be learned for other readers. Well built code isn't always modular in nature. Unlike an assembly line, we can't start with a chassis and add piece by piece to make the final car. Instead, we start with a golf cart someone put together in a hurry (the critical and unavoidable proof-of-concept), and we have to use our assembly line process to convert it into a sports car.