In November 2015 I embarked in a new exciting journey to build an iOS app to cast images and videos from my iPhone to a Chromecast connected TV. All of this in Swift, as a solo developer, as a side project.
In this post I will share some considerations and practices that have helped me scale up to over 4000 lines of code in 3.5 months while keeping technical debt at a minimum and maximise maintainability going forward. Quick preview:
For context, the functionality for the first release is approximately 50% done so I expect the codebase to eventually double. In comparison to all of my previous apps and client projects, I estimate that I’m adding value faster while writing more modular code and less of it - by at least a factor of two.
Without further ado, this is how I work:
Mantra: Design for maintainability and your future self
- Strive to never duplicate code
- ALWAYS keep source files under 200 lines
- Code locality wins. Cohesion
- Don’t scatter over multiple classes code that belongs together.
- Use extensions inside classes to group functionality that does belong together. This makes it easier to factor things out when needed.
- Name things appropriately
- Minimise mutable state
- Think carefully about ownership in the object graph, especially for asyncrhonous calls
- Use ViewModels to drive UI updates
- Always refactor after adding a new feature
- Always test extensively after adding a new feature - AKA fix bugs before adding new code
- Make everything private by default
- Do all of your UI and layout in Interface Builder. Code is not where your presentation layer belongs!
- Error handling is central to application design
- Make errors developer-and-user friendly
- Programmer errors should blow up immediately in your face
- Bonus: use development pods for self-contained code that I’m planning to open source, such as this.
What I have not done so far
- ReactiveSwift: I would love to try this out and leverage the power of Observables in the app but haven’t had the chance yet.
- TDD / BDD / unit testing - though I have thought carefully about dependency injection, and the constraints above force me to keep my classes small.
- Integration tests. As I always fix bugs before adding new features, this doesn’t feel like a strong requirement yet. I have however built a fake/stub for the receiver app so that I can test most of the app when I don’t have a Chromecast device available. Plus, I can switch between fake/real receiver at runtime.
For side projects like this, I found it beneficial to try to make a bit of progress every day, and generally not have more than three days in a row without working on it. This keeps me always focused on the product and I can plan new work or think about how to solve problems on an ongoing basis.
As I’m building this alone I can use a single Google Doc for tracking progress, bugs, TODOs, milestones and day-to-day tasks. At this stage I find this simpler than having dedicated tools for each of these things, as would be the case in most organisations.
Finally, I chose to build this as a side project while spending most of my time doing client work. Benefits:
- Less pressure to deliver and less stress - I can take the time to get the details right
- I can try things out on this app and bring some valuable ideas to my client projects
- I can build this for me and for my users, not for managers or investors
While I’m very happy with the results so far, I’m planning to write a follow up in a couple of months’ time and see if all of the above is still working for me and the project.
I’m now gearing towards a first beta version of my app. I’m determined to make this the best Chromecast app for casting local photos/videos so it would be amazing to get some early user feedback.
How do you build your apps? Do you agree with the above principles? Let me know in the comments below :)