A walkthrough of my rapid web app minimum viable product (MVP) development. Talking you through idea creation, design, build, test, and deployment.
Summary
I designed, built, and launched a minimum viable product (MVP) web application in under 8 hours. While it could have been done in a single day, I did this over several evenings and a weekend or two. (This might be important as you can often solve difficult problems in your head, away from the keyboard while doing other chores).
The app, myFeedium.com, is a twitter-like timeline of stories for Medium.com. This is functionality missing from the core Medium.com product and something I wanted, so I made it myself. If you find it useful or have any feedback please get in touch!
- Email: [email protected]
- Twitter: @craighays
- Or leave me a comment at the bottom of this article
Try the web app: https://myFeedium.com
Generating a Web Application Idea
Like many product creation stories, the idea for myFeedium came from a moment of my own need. I sat down with a cup of coffee and the intention to read the latest posts from people I follow on medium.com. I opened the Android app and realised there was no way to view a timeline of posts from the people I follow. Then, doing the same thing on my laptop, I realised there was no native functionality within the Medium website.
Medium.com generates a story feed for users based on people they follow, their interests, past reading history, current trends, and all sorts of other factors. The feed you get isn’t the latest set of stories that have been published but Medium’s curated list of things they want to show you. What I wanted wasn’t there so I decided to create it myself. Find a gap and fill it.
Basic Design
In my head, I came up with a basic design based on work I’d done in the past. The site would be a static HTML page with javascript that would pull data from my own API and render it inside the page. The API would grab a list of people a user follows from https://medium.com/@craighays/following (or whichever username was entered) then fetch all of their recent posts via the RSS feed https://medium.com/feed/@craighays. Once all of the posts have been gathered they would be sorted by time and displayed to the end-user.
Simple. In theory…
I spent a few minutes poking around inside the Medium.com website to see how data was gathered. There are few different ways to get data including a graphql API but I found those two links have the best performance.
Time spent – 5 minutes.
Total time – 5 minutes.
Picking a Domain Name
As with any project, the first thing I did was spend 20 minutes on a domain registration site trying to find a .com domain name for a name that wasn’t awful. I failed. I settled on myFeedium.com, a name-smash of ‘my feed’ and ‘medium’. It will do for now.
If I was launching a company I’d also want to register Twitter, Facebook, youtube, Instagram, Snapchat, Pinterest, Medium, and other usernames to go with the company brand. As I just wanted to build a tool for myself, I didn’t feel the need to grab any of them.
Time spent – 20 minutes.
Total time – 25 minutes.
Creating a Basic Webpage for my App
With my basic single-page design in mind, I knew that I would fetch data from medium.com and ajax it into the page with jQuery. Therefore, I needed a static web page to work with. I’m an awful web designer at the best of times so I always use templates from people who actually know what they’re doing. And for an extension to the Medium.com website, what better than to view their source code and tailor it to my needs.
I went to the Medium.com homepage, right-clicked the page, hit view-source and copied and pasted the HTML, CSS, and javascript into my own index.html page. Now I had a static, responsive web page that looked exactly like Medium.com.
Using the Chrome developer tools to inspect the source code and highlight elements as I moused over them, I identified bits of the page I didn’t want and removed them from my index.html page. I took out all of the non-functional code that Medium uses for other stuff like click tracking and javascript events that I wouldn’t implement, then I added my own banner, some welcome text to describe the app and how to use it, then a form to submit data. I liked the placeholder lines for articles so I left them in place as filler to show where the content would eventually go after a page load. It looked something like this:
Time spent – 1 hour
Total time – 1 hour 25 minutes
Creating A Logo For My Web App
My static page now needed a logo. What I left out of that screenshot was the Medium logo at the top of the page. While I can justify adapting their HTML code, I can’t justify stealing their logo. That’s not cool. So I Googled ‘what font does Medium use’ and discovered that they’re currently using ‘Noe Display Medium‘. Another quick Google later and I discovered that the developers of the Noe Display font have their own website.
Their site lets you demo the font in action. I typed myFeedium into their demo tool and took a screenshot and that was the logo created:
Medium actually uses SVG rendering for their logo but I didn’t feel the need for that complexity yet. I wanted to spend my time on getting something working instead of being fancy – an image will work just fine for day one.
Next, I needed a favicon to go with the logo so I opened it in photoshop, dropped the ‘my’ and ‘eedium’, and then inverted the colours. Favicon done:
Time spent – 5 minutes
Total time – 1 hour 30 minutes
Creating My Web App’s API
While it would be great to use the client’s browser to fetch data from Medium.com, I would then be forcing users to carry out excessive and repeated cycles of downloading data and processing it in javascript. This isn’t nice on mobile bandwidth or battery usage. I knew I needed to do everything in an API and return the computed answer to end-users in order to give them the best experience. I needed a simple API, so I wrote one in PHP.
The Best Programming Language for Creating Web App MVPs
I’ve been writing PHP since I first got access to the internet. I don’t even know why. At college, they taught us Visual Basic. At University I learned Java, Javascript, C, Perl, and C++. Somewhere I picked up PHP and it’s been my goto web language ever since. The best programing language to use for any MVP is the one that you know inside out. Pick a language you can achieve almost anything with, without resorting to Google or the language documentation every 30 seconds.
For an MVP, speed of development is critical. Your greatest enemy is boredom. Without the gratification of seeing something working soon after you start the project you risk losing interest in the idea. How many half-started projects do you have saved in your Github account? I know I have a lot. Most will never see the light of day. Hundreds of hours of effort gone to waste because I got bored. Don’t get bored.
When speed of development is important, familiarity with the language is key. Don’t try to create an MVP while learning Rails or Django for the first time. Use what you know, even if it sucks. (I don’t actually think PHP sucks, I think it’s awesome, but that’s another article.)
Getting Data And Returning It To The User
My web app has one API call: getFeed.php. When you provide a username it grabs all of the accounts they follow from https://medium.com/@username/following. Then, for each username it finds, it grabs their RSS feed from https://medium.com/feed/@username, cleans up the data, then adds it to a big array. Finally, it sorts the array by publication date and returns HTML to render into the static page. Simple really.
Except I soon discovered that medium.com has a rate limit on the RSS feed. After a few requests, I started getting HTTP 429 responses. I had two choices: add a delay between requests which would make the API really slow, or add some form of caching of responses to minimise the number of requests per minute. I opted for the latter and added a Redis cache.
During testing, I discovered most people follow the same writers. The more traffic the site gets that warmer the Redis cache will remain (in theory). We’ll see how that plays out in practice. Finally, I added some error handling to mask 429s on feeds that weren’t yet in the cache knowing they would be picked up next time around. As for staleness of data, each cached value is set to expire after X minutes so that new author posts will be gathered within a short period of time after publishing without degrading the user experience by removing the feed from the Redis cache to quickly. I still need to tweak the value of X but for now, it feels right.
This was pretty challenging as there were lots of little issues, edge cases, problems, and usability issues that needed fixing. I think I spent most of my time here just trying to get it right.
Testing
Testing is really important. Without proper testing, you risk releasing an awful product that people will hate. That said, my app is so simple I didn’t bother creating any code-based tests, I just did it all by hand. I tested the main functionality, what happens if too many accounts are followed, what happens if none are, what happens if the user doesn’t exist, what if I add bad characters to the username, etc. As I found bugs on my local environment I fixed them and retested. I repeated this until it worked 99% of the time. Occasionally there might be an error due to some unforeseen edge case but overall it’s not that bad.
Time spent – 5 hours
Total time – 6 hours 30 minutes
Deployment to Production
I deployed my application into the Amazon AWS platform using an Elasticache Redis cluster and EC2 instances. I’ve been an Amazon AWS user since it was released to the general public. Each year it gets better and better with more and more features and it’s so easy to use. For this project I only needed:
- An Elasticache Redis cluster
- A loadbalancer
- A EC2 image
I knew that I could deploy and use all of these really quickly. While I would have loved to have wrapped the code in a container and deployed it through ECS or Fargate, or even compiled it to a binary and deployed it to Lambda with an API gateway, they all take too long and time was one of my top priorities. I wanted an MVP I could launch as fast as possible. I can do all of the nice shiny stuff later if I need a better way to scale than EC2 servers. For now, simple is best. Launched is better than perfect.
I managed to get AWS configured quite quickly and fronted it with a Cloudflare reverse proxy for handling DDoS, content caching and distribution, DNS, and all the other good stuff they do. Once that was working everything was good to go.
Time spent – 1 hour
Total time – 7 hours 30 minutes
Post Deployment Fiddling
Once I had a working version online I did some mandatory post-deployment fiddling. I added Google Analytics to measure if anyone was actually using the app or not, I fixed a few formatting issues and some typos and did some general housekeeping.
Time spent – 20 minutes
Total time – 7 hours 50 minutes-ish..
Launching the Web App
It’s difficult to know when to stop. There’s always more to add. Since I first deployed a working version and started using the app myself I started to notice and add more features. I’ve since added a button below each post to view that author’s own feed. Now you can shift the myFeedium point of view from person to person to person. This is another rabbit-hole of content I keep finding myself getting lost in.
I know that I want to add functionality so that I can link directly to a username such as myFeedium.com/craighays and view that person’s feed, but I haven’t done it yet. It’s simple to do but it all takes time. Instead, I decided to leave it as is and start promoting it through articles like this one. I know I’m finding it useful already, I just hope you will too.
Wrapping Up
Once you have an MVP that works, the most important thing to do next is to launch. Stop tweaking it… just launch it. Tell the world, see if really fits the gap you found or if it’s nonsense. Until you launch it you’ll never know.
Try the web app: https://myFeedium.com