A feature-rich, good looking MVP. A tight budget; not necessarily money-wise, but a tough time frame. A client you have never worked with. A hard deadline. Sounds like a project from hell, doesn’t it?
We thought so too when we recently chatted to a potential client who talked us through their startup idea. They had an amazing business idea and concept but lacked the technical know-how to push it through, so they asked us to partner with them. The catch: they had their first pitch with a potential client of theirs in four weeks. We liked their idea and decided to do our best to help them out. Here’s what worked well in this configuration and what we’d do differently next time.
Prologue: The Deliverable
To set the record straight for this story we have to assess what we were actually asked to do. We completely omitted any backend work, as our partners needed a working frontend app they could present to their potential clients. The app should enable the complete workflow to showcase the final feature set. This meant we did a lot of data mocking, but not having to write the backend as well gave us some time. We chose to go with React for our stack configured by Create React App. The result is a somewhat intelligent prototype which showcases two client onboarding processes, built from around 20 pages and highly dynamic forms.
1. Lots and Lots of Communication
A client with a startup idea looks at your deliverable with different eyes than your corporate client looks at their enterprise application. You are working on their baby, their idea and they want it to be perfect and just the way they’ve imagined it. With a small budget and little time, communication between your client and your team is key. We set up a simple Trello board which showed our work in progress and our work queue. With daily calls our client had full transparency of our work load and progress. This helped them understand the effort of specific features and made it easier to prioritise.
2. Continuous Delivery
At smartive we work heavily with GitLab and GitLab CI, so we are used to Continuous Integration and Delivery. This meant that we always had a working application for our client to view, test and play with. We got instantaneous feedback from them and knew which parts of the application required us to invest more, or less time. Organising and prioritising their feedback into our work queue was of course not always easy and might even be a risk in other cases, but that’s a whole other topic.
Delivering software continuously allowed us to iterate as fast as we did without wasting too much time on unnecessary features.
3. Don’t Disregard Testing
You only have four weeks time and you want to get going and not spend useless time on setting up a testing framework. Our team iterated quickly and was on high velocity, so this meant that components and code units were extended, rewritten and removed constantly. Not having tests meant realising mistakes and errors too late — once even on our (public to the client) test environment.
The positive side of this is we were reminded of the importance of automated testing, be it unit, integration or even snapshot testing.
4. Stick with What You Know
Recently though, I have become quite annoyed by Flow’s server mainly due to this issue. Because we do have positive experiences with TypeScript, and apparently the TypeScript + React stack had become quite stable, we decided to opt for this combination. Unfortunately, it didn’t turn out as well as we had hoped for.
We bootstrapped our project with create-react-app-typescript because we have done quite well with Create React App (and customisations) in the past. Our biggest pain points with this stack were (and are):
- Mixing TypeScript with other technologies from the Webpack ecosystem doesn’t work as well as it could. E.g. CSS modules have to be used with require() rather than import statements since TypeScript’s module system works differently.
- Third-party typings are often wrong or out of date.
- PropTypes as types or interfaces don’t always bode well with the TypeScript compiler. The compiler often provides you error messages about IntrinsicAttributes & IntrinsicClassAttributes which don’t really get you any further. We have way more (connect as any)() than I am willing to admit.
- Errors from ts-lint and the TypeScript compiler have cost us more time than type safety has won.
This shouldn’t be interpreted as a TypeScript rant, though. Our love for TypeScript is still very much intact and we’ll continue using it on a daily basis, but we’d think twice about working with this specific stack.
5. Quick, Not Dirty
A short timeframe and an excuse of working on an MVP might trick you into taking a shortcut from time to time. Don’t. When we hacked something and cheated we usually ended up rewriting the code properly within a couple of days. Writing opinionated code is fine, you can make it less so when there’s a use case to reuse it (DRY still counts in an MVP). Make sure it’s decoupled and cohesive and you apply good coding practices as per usual. This will not only reduce your issues during your initial project phase, but also provide you with an already sound base for future development.
With an MVP which makes both us and our clients happy we would definitely do something like this again. We have learned what it takes to move in a high velocity environment with constant change requests and feedback cycles. A more formal process like rapid application development (RAD) might be worth looking into next time to reduce risks and distractions even more. Our team was once again shown that high code quality requirements like testing and clean code are worth the time and effort, not matter the project’s size.