Have you ever noticed that as the size of your program (lines of code) increases, it becomes harder and harder to add new features without breaking stuff? Have you ever wondered how companies manage to create programs that have hundreds of thousands (and sometimes millions) of lines of code?
The secrete is to break stuff down into little manageable pieces.
Break it Down
Take your initial problem, break it down into smaller, logically cohesive chunks. Then break those chunks down further, keep doing this until you have manageable small, cohesive chunks. By a chunk I mean a file, package (collection of files), class, or function.
Characteristics of Good Chunks
Each one of these chunks must be cohesive (have one well defined role/responsibility) in the system (the word “system” refers to all the chunks together). The chunks must be well named (and the name should reflect its role/responsibility). These chunks must have a well defined interface (what their inputs are, what they will output, how they will perform under different conditions, how they will act under error conditions, etc). The description of the role/responsibility and the interface of a chunk must be clearly and consisely documented.
These chunks must also be well tested, to ensure that they truely abide by the interface they set forth.
How to Best Break it Down
A problem can be boken down in so many different ways (i.e. it can be broken down into so many different chunks). Breaking stuff down is an art form. You become better at it with experience, but in general, try to break it down into chunks that just make sense with respect to the domain. Try to break things down in such a way that someone completely new to the system, but experienced with the domain, will look at all the chunks and kinda see why they were broken down this way.
Try to keep things simple, don’t over engineer.
Constantly refactor (i.e. reorganize your chunks, combine some of them, split others, etc) as your understanding of the domain increases and as you progress in your development. Have automated unit, functional, and scenario tests so that you can refactor confidently. Make sure that your automated tests run fast.
Don’t Hack Things in
If it doesn’t fit nicely with the rest of the system, if it’s out of place, take it out, refactor it into other small cohesive chunks that fit nicely with the rest of the system, then put them back in. If you really must hack something in, make sure the hack is not in the interface, but in the details (implementation). That way, the hack doesn’t spread, and when you find time, you can nicely cut it out and replace it with a proper solution.
In order to create a large software system, make sure that you break things down into well named, small, cohesive chunks that logically make sense in the domain. You won’t get it right the first time, so make sure you have fast automated tests in place so that you can refactor confidently.
These guidelines are not limited to single programs. They apply if you are developing a system of many programs as well. In fact, they apply in any system (software or not). Just break things down into little cohesive pieces that make sense in the domain. You won’t get it right the first time, so put things in place that will make it easier to restructure.