Since joining MyWallSt almost 2 years ago, I have been looking for the best ways to manage our development.
MyWallSt is a small company, but we’re constantly growing.
Our current tech team consists of two iOS developers, two Android developers, one designer and one backend developer. One of the Android developers and the designer only joined us in the last 3 months, though, and we can expect to scale more in the future.
So how do we use all the agile techniques and tools to help us manage the work we do?
After reading many articles about different approaches that other companies use, I tried to take the best ideas I could find and adopt them to our own situation. Some of the things I learned were very good on a larger scale, but when applied to a smaller team, just added unnecessary bureaucracy to the flow.
But, after almost two years and many various attempts, we’ve created a development flow for our team — one that I wish I could have read about 2 years ago.
Some of the things I describe might seem obvious, but they just weren’t for me when I started.
At the core of every development is good task management. There are a lot of tools and frameworks out there, but we didn’t know which one would fit to our team and flow.
Last year, we tried to adopt various task management tools, from very simple ones (Trello, Assana, Wrike, ZenHub, Zube) to more complex (Targetprocess, Jira).
I started by signing up for all these tools and testing them without the team. Then, when I thought it might fit in with our development process, we tried to adopt them. The tools we tried out were Trello, Zube (an add-on to Github) and Jira. After few months testing each, we decided to stick with Jira.
It took me a week to get a grip on all the configuration it offers and I estimate that I still only know about 30% of its capabilities. Once that’s over though, you can bend it to fit your process exactly. That was very important for us because it allowed us quickly experiment with different development flows.
Here’s a brief overview of our current setup:
On top of both products, the Product Development maintains Epics (big tasks broken down into smaller stories) and arranges them into a roadmap.
The last part of the set-up is Product Design. This groups our iOS and Android project design tasks into one single view. By doing this, we can prioritize our design work across projects and products better.
This system works for us, especially because we have only one full-time designer across both products which means we are constantly switching between them.
Jira is a powerful tool because of the way you can adjust it, so we made it to suit us.
Agile — Scrum vs Kanban
As the development team grows, methods that worked before simply don’t work anymore.
Just one year ago, while practicing Scrum (2 weeks of planned work with a release at the end) with one developer per project, we discovered that it had become very impractical for us. The amount of work one developer can do in 10 days is limited.
Add to this the necessity of dealing with unexpected customer issues and prioritised bug-fixes, we found ourselves being forced to adjust our plans every two days.
That’s why we switched to Kanban. This is the same workflow as Scrum, but with no 2-week sprints and a soft deadline. This structure allowed us to work at our optimum pace without adding the overhead of too much planning.
All of that changed again recently, however. When the team grew to two developers, we suddenly found that we were bouncing between very busy periods and periods when there were just a few tasks to complete (which we used for lowering our technical debt).
Now that we are growing, we felt that we need to add a bit of the planning overhead in order to maintain better pace and catch flaws in tasks definition earlier. Right now, we are slowly transitioning back to Scrum while maintaining the Kanban structure.
As I said, the processes that worked before simply don’t work as the team grows. The key is to encourage the team to point out things that seem not to be working properly and experiment with different solutions.
Gitflow and Continuous integration
An automated delivery process and continuous integration is crucial to prevent time-wasting. It helps us to know what is currently being built and deliver necessary quick fixes safely.
At MyWallSt, we use Git version control and lite version of Gitflow. We have branch called development with the latest code and feature branches are being created from it. When feature branch is ready, the developer requests merging the changes back to development by opening Pull Request (PR) and requesting code review of fellow developer.
We host our repositories on GitHub because of its great code review features. Each PR also needs to be tested before it can be merged to development, so we have only compilable and fully tested code in development branch.
When looking at possible solution for our Continuous Integration (CI), we started with simple XCode server and then moved to Jenkins. It was so painful to set up and even more painful to maintain.
Then, about a year ago, we discovered Bitrise — an amazing CI tool for both iOS and Android. You can define workflows of steps that are being triggered either automatically (for example, by opening a Pull Request) or manually if needed. At the moment we have three different workflows for each project.
- Triggered when PR was opened —checks out the PR branch, builds the project, and if all tests are passed, gives it an approval for merging.
- Triggered when PR is merged to development — builds the latest development code so we can always get the latest executable (great for QA).
- Triggered based on tag or manually when we want to release to Appstore/Playstore — builds the latest development code and uploads it to TestFlight/Fabric Beta.
All of this, in combination with Jira, ultimately allowed us to automate things. Our development flow has 6 columns.
- Ready for Development — Tasks selected for development.
- Blocked — Tasks that are awaiting decisions or are blocked by other tasks.
- In progress — Tasks each developer is working on.
- Ready for Review — Tasks that are waiting for code review.
- Ready to Test — Tasks that need to be tested by QA.
- Done — Tasks approved by QA.
And here are statuses each task can go to and their allowed flow:
A common problem when tracking the progress of tasks was that every developer needed to move their task as the status of it changed. Someone always forgot to move it though, so the best thing to do was automate it.
When developer starts working on ticket, only thing he/she needs to do is to assign themselves to the task and it automatically moves to the right column based on the work in given feature branch. For example, when branch with given Jira task ID is pushed to remote, the corresponding task is moved to in progress, or when PR is opened, task is moved to Ready for Review.
With this setup, we don’t have to worry about moving tasks and the development board always reflects true state of development instead of relying on people moving cards around.
This is also great when someone new is joining us, they don’t have to learn much about our flow (like When you finish PR, assign task to QA) because the board does it for them.
Communicating Design Solution
One of the greatest design tools we started to use almost two years ago was Zeplin.
Because we are still small team, we can afford to take some time and talk through the solution in a short session before development instead of spending hours building prototypes. This always depends on the task though.
It’s wise to establish one source of truth for design especially when working remotely. You can be sure that developer does it with the same specification as QA is testing it later.
Every developer has their own code style. Some indent their code, some compress everything on one long line. As we hire outside collaborators from time to time, we decided to make sure we can all read each other’s code easily.
Fortunately, there are companies that think about the code style same as we do. With a help of other companies’ code styles published on Github, we created our code style and enforced it everywhere we can (SwiftLint, ktlint).
It is just much simpler to read each other’s code when it’s all written in the same style and there are already tools for that.
Trying to build a development framework from scratch with no comparable examples was difficult. However, by adapting parts of the processes that other businesses have used, we have managed to make a version that suits us.
As the team and number of projects grow, we are going to face new challenges. There’s no one ideal workflow that would fit a team of any size and pace though. The key thing is to constantly evaluate our processes and learn from others who already faced the same problem.