I moved from the Top Friends team to the Rock Riot team, spending probably as many hours into the night coding as I did trying to get a perfect score on YYZ*. Yeah, the game is somewhat addicting.
As we developed the app, we learned some interesting things about our our development practices. I can summarize in three words: "iterate, iterate, iterate". Rather pithy, I know.1
From a developer's point of view, this means implementing a few essential, and basic, practices that minimize regressions, minimize time spent in development, and maximize the number of feasible** options open to product as the features expand and change. I hope, dear readers (both of you), that these little tenets and rubrics seem so elementary to you as to be ridiculous. In my experience listening to the technical debates between freshly-minted C.S.-degreed engineers arguing which über-cool theory is absolutely best for product development over cups of hipster-crack***, I suspect you may be in the minority.
Keep it simple.
No, really. Simple is better. Why? You're not the only nerd reading the code. And even if you are, later on (which might mean the day after tomorrow), you have to understand your own work. A caffeine-fueled brilliant epiphany about the One and True Use of Meta-Classes[tm] applied to a class that makes your fat little avatar eat a fat little hamburger may not make much sense to you after only 5 hours of sleep 3 days from now.
And other people (E.g., all of those other nerds in the office who also eat the Cocoa-Puffs at 3am) need to quickly grok the structures you've just committed. Complaining that "those guys" are just stupid when they can't understand your obviously brilliant implementation of virtual-hamburger-consumption doesn't help your start-up reach that nice fat exit any more quickly (in fact, it probably delays it as you add to the technical debt that must be paid eventually).
Usually, simple code is quicker to write and conforms to the essential language standard employed by fellow engineers, is clearly documented, and is obviously located. This is very important in a fast-moving environment, and I'll get to why in a minute if it isn't already obvious.
Simple does not mean tightly-coupled, and it does not mean non-extensible. In fact, writing simple, easy-to-understand code is not mutually exclusive to writing easily-extensible software and easily-modifiable systems.
By the way, see what I did there? I segued from code to systems. I'm clever that way, stick with me here. We're not just writing code, we're creating systems. Systems basically represent a snapshot (and therefore by definition static) of some real-world business process, therefore we'll need to insure that these systems are as easily mutable as possible in order to follow the ever-changing (and by definition, dynamic) business model (strategy, goals, tactics, measurement).
Keep it loosely-coupled.
Keep it easily modifiable and easily extensible.
In my experience, with practice it takes no longer to write code that is loosely-coupled than it does code that it tightly coupled. It does, however, take much more time and/or resources to modify systems built with tightly-coupled components than it does to modify systems built with loosely-coupled components. Hey, want to integrate that nice thingmawibble that speaks JSON into your system that speaks XML? It should be easy. Point the important components on your side of the fence to the "GimmeJSON" component instead of the "GimmeXML" method, and transmit to the thingamawibble.
Keep it short, sharp, and simple
prototype in iterations, salvage and destroy, build for realz in iterations
One rubric of startup success is to launch the simplest (and probably ugliest) product or feature possible, and then begin a cycle of iteration. The same idea can be applied to writing code, within reason. Caveat emptor - YMMV, and it will probably take some trials and successes/failures to find that sweet spot of how good enough is "good enough". GEFA2 is a good rule of thumb, as it's a reminder that the code isn't permanent. Build with the idea that it's a trial run. Once you have an idea as to whether this sucker's going to fly, that these dogs are going to hunt and that these overused metaphors are about to end, invest more time into implementing a more permanent solution. I find that I can quickly salvage many of the pieces from the "alpha" version, and re-implement them in an iteration-friendly system that's by definition easily extensible.3
The combination of simple, short, loosely-coupled, and documented will not only provide a code platform that's conducive to change, but also allows you to salvage parts, quickly discard parts, and move to the next version of the product relatively quickly and easily (and painlessly, if we've done it right).
Make it easy to find (or, "Where the hell did I leave my shoes?")
"Hey, where's the audio file transmogrifier tool script?"Yeah, we all know that guy. Don't be that guy. Basically, put your code where other can find it, and where it should be obvious. This goes for transient modules as well as for stacks of classes. "Dude, just grep|scan|locate|read the code and you'll find it" is rude, and lazy in the wrong way. It's also a good way to slow down development. Imagine your engineers spending as much time trying to locate re-usable utilities as it does to write new code. Kinda silly, and unnecessary. Good lazy is to, for example, put your dev tools in a place called (ok, wait for it...) 'tools'. OMG. So simple. This also applies to location of new methods in existing code. Putting a localized method way up in the stack where everyone loads it, regardless of how orthagonal their application is to yours, is probably a bad idea. Placing your "buy buns" method for your "Hamburger City Farm" product in a module meant for controlling all incoming http requests for your company is, as they say, BAD.4
"It's in a directory called 'car_parts' under jason/whatever/things/cabinet/stuff/misc/noisy".
"Excuse me, where can I find the biography of Ulysses S. Grant?"I know, You're thinking "What the hell, who does this?". You'd be surprised, my friend, you'd be surprised. Luckily, it's not a common occurrence at Slide. We're somewhat fanatic about putting code where it belongs, and I've found that I've become spoiled in that when I look for code, I find it within a few seconds.
"Teen Romance, next to New Age"
Why is all of this important (at least, in my opinion)? It helps your company succeed. And unless you're a geek in a basement, h4xx0r1ng away without responsibility to anyone, you'll need to work with other engineers and be a part of a group that excels at quickly building robust systems.
*Rush, "Moving Pictures"
** "feasible" as defined by you and your team. YMMV.
*** Blue Bottle coffee
1. I'm not going to discuss business stuff because (a) I'm not a PM, and (b) I'm not really interested in spilling Slide's business knowledge to the entire blogosphere.
2. "Good Enough for Alpha"
3. I realize that this is all pretty vague. There are many places on the web to get info on loosely-coupled code practices, proper OOD, self-documenting code, bug-preventive practices, and so on. The really important point here is that the best way to learn this stuff is with practice. Trial and success/trial and error is the only way. Build some systems and hurt yourself a few times, ask a few questions, and you'll probably quite quickly find the correct answers.
4. I know, this is also an extreme example, but it serves the discussion and isn't too far off from a real-world example I once corrected.