I thought it might be worthwhile to formulate a technical checklist for a software project – gather all the questions you need answered before you should begin coding the business logic itself. To most of these questions there are only one or two possible answers, and StackOverflow can help you choose between them if you don’t know already which is the best solution for you.
It’s a long list, but I really believe all or most of these will bite you in the ass if you delay them.
1. Programming language / framework
This is the first choice because it influences everything else. All of us have our favorite languages, and our degree of proficiency with them varies. Besides this factor (which may turn out to be huge), consider:
- Performance characteristics. This is probably not relevant today to over 95% of software projects, as most languages will have a reference implementation or two that will be fast enough – but don’t go writing embedded code in Ruby (I’d take this chance to refute once and for all the illusion that some people still maintain – C/C++ is not faster than .Net or Java, it’s just more predictable).
- Important 3rd party libraries. If your business application just has to have Lucene 2.4, and ports of Lucene to other languages are lacking in functionality, this pretty much limits you to Java. If you’re writing a GUI-rich application targeted at Windows, then .Net is probably your safest bet.
- This should include a mocking framework, though I usually tend to write integration tests more than unit tests.
- Think about integration with your test runner – for example, Resharper didn’t support running MSTest tests two years ago (when we were using it, mainly because we didn’t know any better).
- Unit tests are not enough – integration tests are the only thing that gives confidence in the actual end-to-end product. For strong TDD advocates: System Tests are also very valuable as they are the only thing that tests flows on the entire system, and not on a single component-path.
- I’ve only recently started applying this technique heavily, and it’s a beauty. It allows writing isolated unit tests and easy mocking, and helps lifetime management (e.g. no need to hand code the Singleton pattern by hand). A good framework will ease your life, not complicate it.
- When implementing your choice of IOC framework, remember that wiring it up for integration tests is not the necessarily same wireup for actual production code.
4. Presentation Tier
Most projects need one, whether it’s a web or desktop application.
5. Data Tier
- How do you plan to store and access your data? Can your site be database-driven? Or do you need to go the NO-SQL path? You might want to combine both – use a database to store most of your data, but use another place to store performance-critical data.
- Object Relation Mapping – You usually will not want to hand-craft your SQL, but rather use an ORM (we’re all object oriented here, right?).
6. Communication Layer
If your project have several independent components or services, you should choose a communication model. Do they communicate over the database, using direct RPC invocations, or message passing via a Message Bus?
- Logging everything to a central database if in my experience the best solution. Use a logging framework (and preferably pick one that has a simple error level scheme and allows built-in log formatting).
- Make sue your logging doesn’t hurt your performance (opening a new connection to the DB for every log is a bad idea), but don’t prematurely optimize it.
- Do not scatter your logs – a unified logging scheme is crucial in analyzing application errors, don’t log some events to the DB and other to file.
- I find it useful to automatically fail unit tests that raise errors. Even if the class under test behaved as expected, it might have reported an error condition internally, in which case you want to know about it. Use an in-memory appender, collect all the error/fatal logs and assert there are none – except for tests in which you specifically feed your code erroneous input.
- Decide on a sensible API to access configuration from code. You can use your language’s native configuration mechanism or home grow your own.
- Decide on how to maintain configuration files. Who is responsible for updating them? Which configurations are mandatory, which are optional? Is the configuration itself (not the schema) version controlled?
9. Release Documentation
- Release notes / changelog – A simple (source controlled) text file is usually enough, as it gives crucial information on what a build contains. Should include new features, bug fixes, new known issues, and of course how-to deployment instructions.
- Configuration documentation – especially on large teams, you should maintain a single place where all mandatory configurations are documented. This makes it easy for anyone to configure and run the system.
10. Packaging and Deployment
- Have your build process package an entire release into a self-contained package.
- Have your builds versioned – every commit to source control should increase the revision number, and the version should be integrated into the assemblies automatically – this ensures you always know what version you’re running.
- Depending on your IT staff and how complicated manual deployment is, you might want to invest in a deployment script – a script that gets a release package and does everything (or almost everything) need in order to deploy it. This is a prerequisite for writing effective system tests.
- Source control: SVN, TFS, Git, whatever. Choose one (according to your needs and budget) and put everything you develop under it. One painful issue is your branch management. Some prefer to work constantly on a single always-stable trunk, other prefer feature branches. The choice is affected by your chosen SCM tool, the size of your team, and the level of experience you have with the tool.
- Build System – Unit tests that are never or seldom run are hardly effective. Use TeamCity to make sure your code is always well tested (at least as well tested as you thought).
- IDE – Some programming languages have only one significant IDE, other have a few.
- (Note – I don’t really consider Visual Studio to be an IDE without Resharper)
- Bug tracking – have a simple place to collect and process bugs.
- Feature and backlog management – have an easy-to-access place that shows you and the entire team: What features are you currently working on, what tasks are left to do in order to complete features, what prioritized features are on the backlog – this is crucial to help you choose what to do next (I prefer the sprint-based approach)
- Documentation standard. It can be a wiki, shared folders, Google Docs, or (ugh) SharePoint, but you should decide on a single organizational scheme. I strongly suggest that you not send documents as attachments, because then you can’t tell when they change.
- Basic IT – Backup, shared storage, VPN, email, …
Do you agree with this list? What did I miss? What can be delayed for later stages in the project?