When I do stuff myself (one programmer) I try to break it down in blocks with as few as practical defined inputs and outputs. Easier to debug a small black box, then move on to the next one. Plus, if you come up with a better way to do the job of a given black box, you just recode it and drop it in, confident you're not breaking 6 other boxes.
That’s how UNIX was built a series of function boxes. But then the need to tune always gets the best of them, and wrecks the whole plan — sigh.