After working on a number of client and internal projects, we came up with a standard development process that we try to adhere to. We do this because we know it works for us. It helps us produce high quality software, minimize headaches, and improves development speed. In the end, it creates results for our clients, which is our ultimate goal of software development.
Not all projects and clients are the same though, so we have to modify our process to fit the need. We probably keep about 80% of our process but tweak variables depending on the client. We change things like which software tools we are using, what mode of communication we use, and the length of a standard sprint. When making these tweaks, we take into account things like complexity of the software, number of team members, how involved the client wants to be, and skill and churn of the development team.
Preparing for Battle (Tools)
Before we even start the project we want to make sure we have the tools and processes to be a highly effective development team. Since we are a small team we try to leverage as many services as possible. This allows us to accomplish more with limited resources and focus on what we do best.
For communication we use is Slack, and Google hangouts. Slack is great for automated notification on checkins, and quickly communicating with team members about the project. Google hangouts is essential for communicating with remote teams and clients.
For project management, we put all our tasks, plans, and bugs into Trello. This gives us a single location to see the status of the whole project. We’ve used other tools like asana, pivotal, and basecamp with different clients, but we prefer trello because of its simple interface and flexibility.
For source control we use Git, and use Bitbucket for our repository. We also use Github for open source projects and some client projects.
When we deploy our application we use Codeship or a similar service for continuous integration. This automatically runs our tests for us and automatically deploys our code to staging and production servers. It allows us to maintain code quality and ship our work to production faster.
We love to host our applications on Heroku. Heroku makes it super easy for us to deploy to production, it takes care of all server management, and it allows us to scale up with a click of a button. Many clients can’t use Heroku, so we are flexible to work within the company’s hosting requirements.
Overall, we believe that this mix of tools has allowed us to develop software faster, respond to customer needs quicker, and maintain a higher standard of code.
The Human Aspect (Process)
At the beginning of any project we like to do a road mapping session. A road mapping session helps define the customer scenarios, identify goals, understand more about a client’s business, feature priorities, and longer term milestones. Milestones are typically 1 month long and we tackle them one at a time. After a milestone is over we reevaluate where we are, update the schedule, and make any other necessary project adjustments.
Within a monthly milestone we typically work in the following way.
- Break down the monthly milestone into weekly goals and plans
- Before each week, prioritize and assign tasks to team members
- Daily check ins, to go over what we did the previous day, what we are going to do today, and unblock anyone who is waiting on another team member.
- At the end of the week / beginning of the next week, evaluate where we are and see what adjustments need to be made to meet the monthly milestone.
We found that having this type of structure has helped us set realistic timelines, respond to unexpected delays quickly, and communicate that with clients. Also, this type of structure allows a client to be involved as much or as little as possible. If the engagement is more of a team augmentation deal, then we would have them involved in the daily scrum. If weekly sync ups are good enough we’d communicate the project status at the turn of each week. Monthly sync ups are possible, but rare. We typically prefer the client to be more engaged for a tighter feedback loop which leads to a better product.
The Struggle is Real (Code & Git)
While coding we maintain consistent coding standards and styles. We follow Thoughtbot’s style guide augmented by a couple of own style rules. This helps keep the code consistent and speeds up development.
As mentioned above, we use git for our source control and use bitbucket to host our repositories. Git is a distributed source control and is popular among open source projects and startups. Its easy to use and most web developers know how to use it.
When we are deep in code, we make sure that we have well organized branches and checkins for git. For a typical project, we create at least 2 major branches, Master, and Develop. Develop is where we actively develop and check in new code. This should be stable but might not represent what is on production. The Master branch is basically what we currently have on production. For larger projects we might have staging and test branches, as well as versioned release branches.
When developing a feature, each developer creates a separate feature branches off of the develop branch to work on their code. Once the feature is finished, they do a pull request to merge it back into develop. We try to rebase branches when it doesn’t cause too much trouble, otherwise we stick to merging.
For commit messages we follow the popular format described in “A note about commit message” by Tim Pope. When in doubt, be over descriptive rather than less descriptive.
Shipping quality code (Testing)
Automated tests for software is a must. Succinctly, it saves the client time and money in the long run and reduces the occurrence of Oh Sh*t! moments. Automation increases the short term development time, however it keeps the product consistently stable. This allows developers to continue to keep a good development pace even when the product gets complicated. It is also invaluable in maintaining product integrity when you add new team members.
We write unit and end to end tests. We like to develop tests while we develop features. We also use tools that automatically run our tests (like guard) so it doesn’t slow down our development speed. Depending on where we are in the project, how many developers are working on it, or a host of other variables, we might focus only on priority one tests that cover core scenarios. Different scenarios and clients might require more comprehensive tests that cover all edge cases.
When automation is not appropriate, like visually inspecting the user interface, we fall back to manual testing. When manually testing, we typically test on the most recent versions plus one older version for all major browsers (Chrome, Firefox, Safari, and IE). We also typically test the major mobile browsers on mobile devices (iPad, iPhone, and Android). This typically suits the requirement of most clients, however some clients might have specific needs where a legacy browser or device also needs to be tested. In such a case we would add it to our test matrix.
While developing, developers are responsible for running tests on their feature branch before merging with the common develop branch. Using the automated test runners gives developers instant feedback on relevant tests. On top of that, our continuous integration service will automatically run the complete test suite. When everything on develop passes all the automated tests, and the manual tests, we can be confident that the app is ready for production.
Winter is Coming (Summary)
Overall, having a good set of consistent tools and processes, helps us be a more effective team. But that doesn’t mean we stand still. We are constantly looking for new and better ways to develop software. When new techniques or tools become available, and we find that they help us write better code, faster, we’ll incorporate them into how we work. I hope that this give you a little insight on how we develop software! One question for you is how do you develop software?