Skip to content

Instantly share code, notes, and snippets.

@Nickersoft
Created December 7, 2018 01:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Nickersoft/db647d99e0ad99ed133e641981f3b11b to your computer and use it in GitHub Desktop.
Save Nickersoft/db647d99e0ad99ed133e641981f3b11b to your computer and use it in GitHub Desktop.

The Toxicity of the MVP

Introduction

In 2014, I began my first internship. It was my first time working professionally in my field, and being a novice with virtually no industry experience, I was hired by the smallest startup imaginable. I sat alongside the two founders inside a tiny garage, working on a codebase written in VBScript and ASP.NET. To this day, my work there continues to be the first and only time I've encountered Visual Basic in a professional environment.

I remember being immediately off-put by the company's choice to build a brand new product using decade-old technology, so I asked the co-founder about his decision to use VBScript.

"It was what I knew best at the time."

Unfortunately, this is far too often the case. Devs build MVPs using poor design, outdated tech, and infrastructure that cannot scale. Once the product takes off, constant shifts in prioritization eventually lead to insurmountable tech debt.

The result is always one of two outcomes: the debt is left as-is or chunks of time are carved out to rebuild core infrastructure instead of building product.

Much of this dilemma is rooted in the ideology that any minimum viable products (MVPs) should be quick, dirty, and cheap. In the words of Michael Seibel, Y-Combinator partner: "if it takes more than a month to build, it's not an MVP." This mentality has the potential trick entrepreneurs into believing they must sacrifice their tech for the sake of producing deliverables. That said, a month can be more than enouugh for most products – given that you build it right.

In this article, we'll be exploring ways to ensure an MVP doesn't suck.

Why Does This Matter?

As mentioned in my previous article, first impressions are everything. While that article discussed the importance of a product's visual design, the actual usability of a product is equally as important. When I began work on the first iteration of Linguistic, I chose React Native as the springboard for its development. I believed that using a framework that allows developers to build for two platforms at once would allow me to spit out the fastest app I could. Yet a year or so into development, despite being feature complete, the app was riddled with bugs and performance issues. The behavior between platforms was inconsistent – what might be a delight for iOS users could be hell for Android users, and vice versa.

While I was able to build something that would allow me to deliver an app to the most amount of people possible, it was a product that was painful to use and maintain. It didn't put users first. If users installs software for the first time and it's incredibly buggy or unperformant, they will likely never return to it. Most importantly, they won't take your product seriously.

You can build a product fast or you can build it right. If you build it right, then every future iteration of your software will be fast. If you build it fast, you get to ship product but risk the potential of an unnecessary code rewrite in the future.

At The Corner of Smart & Speedy

In an ideal world, all MVPs would be planned and executed in the smartest, fastest way possible that doesn't compromise vision, design, or usability. Unfortunately this is rarely the case. Some of my first projects were written using Visual Basic, PHP, and vanilla JavaScript, and went through multiple rewrites until they were deemed remotely usable or maintainable.

I found there always comes an "oh f***" moment, in which you realize your tech stack is not structured well enough to deliver features at the speed you need and you realize an impending rewrite is inevitable. For me, this moment has resulted in the death of far too many side projects over the years.

So all this said, what can be done to prevent it from happening? How can you avoid the bloat and deliver an MVP that knocks it out of the park?

Realize The Requirements

Before diving headfirst into a product, consider what your requirements will be ahead of time and allow them to influence your design decisions. Can the entirety of your app run as a single Node.js application? Will it need to make calls to external APIs? Does your app rely on data from the cloud or is local storage sufficient? While these questions may seem trivial, they will help guide you through the remaining steps and build better software.

Example: You're building a 3D modeling app for desktop. While Electron is by far the easiest way to spin up a new desktop app, using Electron would require your app to run on Chrome's WebGL engine. If your requirements stop at building very basic models, this may be fine. However, if your goal is to build a high-performance, cutting-edge, 3D desktop suite, native is the way to go.

Adopt An Architecture

Though varying in degrees of applicability, software architectures allow you to build code with structure and integrity. They stop you from asking questions such as "where should I put this logic?" and improve codebase navigation. While the most popular architecture is Modal-View-Controller MVC, there are many others as well, such as MVVM, MVP, VIP, VIPER. Which you use very much depends on the needs of your software. Furthermore, certain frameworks may use their own architectures or app structures, such as Angular or React.

In my experience, the following architectures work best for the following products*:

  • MVC: Java or C++ desktop applications, non-JS web (PHP, Ruby, etc.) apps, very tiny mobile apps
  • MVVM: Android apps, Windows desktop apps
  • MVP: Windows and Java desktop apps, PHP web apps
  • VIPER: macOS or iOS apps (sometimes you can get away with MVVM if the app is simple enough)
  • React / Angular / Vue: JavaScript web apps

Example: You're building a PHP application. You can either write everything as you go, with all route, business, and presentation logic present within a single *.php file, or you can adopt the MVC architecture through a framework such as Laravel. Laravel would provide structure to your codebase, allowing you and other developers to quickly find the logic you're looking for.

*Please do not accept these suggestions as gospel. Software architecture can be a very touchy subject, and I only mean for this list to act as a very broad jumping-off point.

Ready For The Ramp-Up

While building an initial product, it is crucial that your approach allows for you to develop new features as quickly as possible. For example, the static site generator Gatsby will automatically compile a directory of .jsx files to unique page routes out-of-the-box. Need a new page for user profiles? Bam. Just add a single React component and leave the routing up to Gatsby.

That's what I'm talking about.

Other situations may require more work. The good news is, if you've already adopted an architecture, you're already halfway there. In the case of Linguistic, whose primary product is a mobile app, VIPER + custom XCode templates are used to rapidly add new screens to the app.

Example: You're writing a multi-page web application. You start out by putting individual template files into a views directory, and writing individual routes for each view. However, as your application grows, adding custom logic for each individual route becomes cumbersome. An easier approach would be to write more comprehensive logic that automatically serves each of these files as a route based on certain criteria, despite the slightly longer implementation time.

Reduce, Reuse, Recycle

If you ask any web developer nowadays how they might approach a new project, most will say they'd use component libraries such as Angular, React, and Vue. The reasoning is simple: modularity. By breaking a web app into modular, reusable components, code duplication is vastly minimized, and site-wide changes can occur in a central module that propagates throughout the app. This approach makes you code easier to maintain, easier to test, and easier to extend your code in the long term.

The idea of modularity in web apps has in-fact become so popular that the concept has bled into other areas of the tech realm as well, such as iOS and Android development. Below are some frameworks and methods that can help you modularize each part of your MVP:

For a brief overview on modular programming, I suggest reading Wikipedia. For a more in-depth look at modularity regarding your tech stack, I would do some additional research before beginning.

Example: You need to build a header for your web app whose links are persistent across your webpage. You can either copy-and-paste the DOM markup for the header on a case-by-case basis and style it using global CSS, or you can take a little bit more time and create a shared reusable header component. With a shared component, you will only need to update a single file to update the header on every page of your app.

Embrace the Ecosystem

Lastly, when deciding on an architecture or framework to achieve any of the above goals, ensure whatever you choose has good documentation, a good community, and (preferably) good maintenance. This step is particularly tricky considering how rapidly new frameworks come and go. It is usually fairly safe to bet on tech stacks that are at this point "too big to fail", such as Node (8+ years old), .NET (15+ years old), Cocoa (10+ years old), or Java (20+ years old).

Frameworks such as React and Angular are fairly new to the game, having only been around for less than 10 years, so only time will tell. What is important is that you and your developers will be able to always find the resources you need to continue building your product well into the future. A decent indicator of a framework's support may be how many StackOverflow questions exist for it, its GitHub star count, and its GitHub contributor activity.

It's important to note an exception to the rule: sometimes you have no choice. Take for example Apollo's iOS library: it is poorly maintained, poorly documented, but still remains as one of the most popular, if not only, solutions for using GraphQL on iOS (unless you want to write your own framework).

Example: You've followed all the steps above and have found a hot new MVC framework for your MVP: SkyMVC. It checks all of the boxes: it enforces the MVC architecture, supports reusable components, and scaffolds your core app features for you. However, it only has 96 GitHub stars. It was built by a guy named Devin from the Ukraine and last updated nine months ago. No one online is asking about it. It has a handful of README files in the repo, but other than that no documentation. Should you trust this library to build your production app? Didn't think so.

In Conclusion

Now before you raise your pitchforks and claim that much of this may be overkill for a simple MVP, realize that these are simply considerations for when you're building your next big product. You don't have to use a heavy framework like React or a complex architecture like VIPER if you think it's overkill. I just ask that you consider the design and infrastructure of your system before you begin tossing it together with the first tool that comes to mind. If validation is a concern of yours, be sure to tell people about your MVP while developing it. At the beginning of this year I told Reddit about Linguistic and received much-needed validation that way.

Many devs don't realize the importance of planning an MVP, and as one developer who has dealt with way too much tech debt in his life, I just ask that you be smart before you start.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment