Overview

This is the first part of my blog series about launching a Software as a Service (SaaS) product. I intend for this series to be a collection of the lessons I’ve learnt along the way, and is meant to be an educational experience. Because learning new things is one of my motivations there will be times where I explore DIYing portions of the project that should typically be offloaded to a third-party.

Table of Contents

What is Software as a Service?

Software as a service (SaaS) is a common method for licensing, and delivering web based applications. SaaS allows for clients to use software without having to manage, or install anything. Revenue is typically generated by charging a subscription based membership monthly, or yearly.

SaaS makes it easier for entrepreneurs to run a software company as it reduces the cost of distribution to almost zero. At the same time it opens up the possibility of creating a continuous integration (CI) / delivery (CD) pipeline.

One of the biggest advantages in SaaS is since the software is hosted remotely, it becomes much easier to release updates. You don’t need to worry about getting every client to update their software, and you won’t have to support multiple versions at once.

This Project

I’d like to preface this section by mentioning that my two favorite hobbies are cars, and coding. If I’m not working on one, then I’m likely working on the other. I enjoy doing my own maintenance, and repairs on my vehicles because it let’s me ensure things were done right, and I can go the extra mile. The biggest downside to this however, is that I accumulate a lot of small receipts for parts or supplies needed. These receipts are often lost within a week of the repair, and it can be a real pain to track one down when I need to return or warranty out a part.

That’s where this project comes into play. I plan on building a vehicle maintenance logging application that will allow users to record services or repairs performed, upload their receipts, and schedule reminders for upcoming maintenance. I’ve picked this project because it’s a problem I struggle with, and it’s something I’m passionate about.

SaaS is inherently boring. It’s so boring that unless you can find a problem that you struggle with, or find value in the solution, and plan to use it yourself, then you’ll likely fail due to a loss of motivation. That’s why I’ve picked this project, the scope isn’t too large, and solves a problem I deal with quite often.

Launch Day Isn’t Magical

Unless the product is something absolutely amazing (which we all like to think our projects are, but probably aren’t sadly) then there isn’t some massive group of users waiting to use it. That’s why you need to start building your product’s online presence as soon as possible to help attract potential customers.

This can be done through methods such as social media, building a landing page, and more. I’ve decided to start off with building a landing page as it felt like the perfect practice for going through the steps of releasing software into the wild.

The Landing Page

The landing page is the first interaction potential customers will have with your product. It doesn’t need to be over the top, but it should be visually appealing, and not look slapped together. There’s an abundance of resources written by better qualified authors on what a good landing page is comprised of so I’d recommend checking them out:

I decided to DIY this portion of the project myself since it seemed like a fun little challenge. There’s already plenty of services out there such as LaunchRock or Unbounce but I wanted to see what it took to publish my own.

In the end, this is what I came up with:

The Tech Stack

The landing page is hosted via DigitalOcean. They have a very budget friendly $5/mo tier droplet, and an amazing collection of how to articles for noobs like me. The server itself is running Ubuntu, and I’m using Nginx as a reverse proxy.

The project itself is built on Node.js and uses TypeScript, Express, SQLite, and Helmet. I decided against using a templating engine such as React or Angular since it felt like hammering in a nail using a sledge hammer, and would bloat the project. I also decided against using an ORM since the only thing stored in the database is emails, and their date of entry. I did opt to use the CSS library Bootstrap to help speed up development of the web page itself, but did not include JQuery, or any of their JavaScript.

To handle automatically restarting the server when it crashes I’m using PM2. PM2 is pretty easy to set up, and opens up the door for a continuous deployment pipeline down the road.

Server Side

The code to run the server is so small that I was tempted to write everything in a single file. In the end I decided to split it up into 3 files that way I could write a promise based wrapper around SQLite such that I could use the async / await keywords TypeScript offers.

Like other Node.js projects, the entry point is index.ts. This simply wraps a try catch around everything and prepares the server and database. The real magic takes place in server.ts.

To help serve static files I’m using the Express.static() middleware. Everything that should be served to users is located under the /static/ directory of the project.

The server itself only listens on three different routes.

  • / - User visiting the page, serve them the html / css / js
  • /subscribe/ - The user has submitted an email, save it to the database
  • /robots.txt - The site is being crawled, and the bot wants the robots.txt file
        //Handle web requests
        this._app.get('/', async (req, res) => {
            res.sendFile(Path.resolve('static/main.html'));
        });

        //Handle requests to subscribe
        //It's expecting a object with an email property
        this._app.post('/subscribe', async (req, res) => {
            if (req.body.email == null) {
                res.sendStatus(400);
            }
            else {
                let email: string = req.body.email;

                if (!this._isValidEmail(email)) {
                    res.sendStatus(400);
                }
                //All good. Add the email
                else {
                    try {
                        await this._database.execute("INSERT INTO Contact VALUES(?, DATETIME('now'))", [email]);
                        res.sendStatus(200);
                    }
                    catch (err) {
                        console.error(err);
                        res.sendStatus(500);
                    }
                }
            }
        });

        /**
         * Request to get the robots.txt
         */
        this._app.get('/robots.txt', async (req, res) => {
            res.sendFile(Path.resolve('static/robots.txt'));
        });

Client Side

The html for the page is located in /static/page.html (creative right?), and requires a few other resources such as style.css, script.js along with a couple images. The only purpose of the JavaScript on the page is to wire up the send button, and send off the user’s email to the server.

The client side code is as follows:

(function () {
    let sendButton   = document.getElementById('button-send');
    let emailTextbox = document.getElementById('textbox-email');
    let successMsg   = document.getElementById('good-message');
    let errorMsg     = document.getElementById('bad-message');

    //Prepare the send button
    sendButton.addEventListener('click', sendRequest);

    /**
     * Send a subscribe request to the server
     */
    function sendRequest() {
        let httpRequest = new XMLHttpRequest();

        //Does it have an email address in it?
        if(!/^\w+([\.-]?\w+)*@\w+([\.-]?\w+)*(\.\w{2,3})+$/.test(emailTextbox.value)) {
            alert('Please enter a valid email.')
            return;
        }

        httpRequest.open('POST', 'http://mechaniclog.net/subscribe', true);
        httpRequest.setRequestHeader('Content-Type', 'application/json');

        httpRequest.send(JSON.stringify({
            email: emailTextbox.value
        }));

        //Listen for a response
        httpRequest.onload = function () {
            if (this.status == 200) {
                successMsg.className = 'row';
                errorMsg.className   = 'row d-none';
            }
            else {
                successMsg.className = 'row d-none';
                errorMsg.className   = 'row';
            }

            document.getElementById('input-row').className ='row d-none';
        };
    }
})();

Thanks to Bootstrap’s grid I was able to design a page that resized automatically to cater to mobile users.

A nice feature offered by FireFox, and Chrome is the ability to view the web page as a mobile user via their development tools. These tools should not be used as a replacement to an actual test device, but can help speed up prototyping.

I learnt this lesson the hard way as I only tested via FireFox’s dev tools, and it backfired on me after launching and loading up the site on my phone. The site looked like garbage all because I forgot one little tag.

    <meta name="viewport" content="width=device-width, initial-scale=1">

Smaller devices such as phones or tablets render web pages in a different manner than computers. They render using a “virtual viewport” which allows them to display the entire web page at once. From there the user can zoom or reposition their view to a more readable size.

This tag was introduced by Apple in an attempt to make web pages that aren’t optimized for mobile look good. Initially only Safari supported it, but “many other mobile browsers now support this tag, although it is not part of any web standard” [1].

Even if you don’t plan on focusing on the mobile market, you should still prepare a mobile friendly site. As of 2018, of all web pages served, 52% were served to mobile users [2]. Nobody cares for a site that doesn’t look good on mobile, and there’s plenty of resources available to help with designing responsive sites.

If your interested in seeing the site live you can visit it at: http://mechaniclog.net/.

If you would like to see the code behind it check out the Github repository.

Photo

My name's Eddie Abbondanzio, and I'm a full time Software Developer. Programming is my favorite hobby, and I love working on anything web related, and my own personal projects. If I'm not programming, then I'm likely working on one of my cars.