Never Share Your Secrets (Secret Manager and Azure Application Settings)

secret-manager-tool-azure-app-service-2

It’s important to keep app secrets out of our codes. Most of the app secrets are however still found in .config files. This way of handling app secrets becomes very risky when the codes are on public repository.

Thus, they are people put some dummy text in the .config files and inform the teammates to enter their respective app secrets. Things go ugly when this kind of “common understanding” among the teammates is messed up.

i-made-a-mistake-cannot-be-reversed

The moment when your app secrets are published on Github public repo. (Image from “Kono Aozora ni Yakusoku o”)

Secret Manager Tool

So when I am working on the dotnet.sg website, which is an ASP .NET Core project, I use the Secret Manager tool.It offers a way to store sensitive data such as app secrets in our local development machine.

To use the tool, firstly, I need to add it in project.json as follows.

{
    "userSecretsId": "aspnet-CommunityWeb-...",
    ...
    "tools": {
        ...
        "Microsoft.Extensions.SecretManager.Tools": "1.0.0-preview2-final"
    }
}

Due to the fact that the Secret Manager tool makes use of project specific configuration settings kept in user profile, we need to specify a userSecretsId value in the project.json as well.

After that, I can start storing the app secrets in the Secret Manager tool by entering the following command in the project directory.

$ dotnet user-secrets set AppSettings:MeetupWebApiKey ""

Take note that currently (Jan 2017) the values stored in the Secret Manager tool are not encrypted. So, it is just for development only.

As shown in the example above, the name of the secret is “AppSettings:MeetupWebApiKey”. This is because in the appsettings.json, I have the following.

{
    "AppSettings": {
        "MeetupWebApiKey": ""
    },
    ...
}

Alright, now the API key is stored in the Secret Manager tool, how is it accessed from the code?

By default, appsettings.json is already loaded in startup.cs. However, we still need to add the following bolded lines in startup.js to enable User Secrets as part of our configuration in the Startup constructor.

public class Startup
{
    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(env.ContentRootPath)
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
            
        if (env.IsDevelopment())
        {
            builder.AddUserSecrets();
        }

        builder.AddEnvironmentVariables();

        Configuration = builder.Build();
    }
    ...
}

Then in the Models folder, I create a new class called AppSettings which will be used later when we load the app secrets:

public class AppSettings
{
    public string MeetupWebApiKey { get; set; }

    ...
}

So, let’s say I want to use the key in the HomeController, I just need to do the following.

public class HomeController : Controller
{
    private readonly AppSettings _appSettings;

    public HomeController(IOptions appSettings appSettings)
    {
        _appSettings = appSettings.Value;
    }

    public async Task Index()
    {
        string meetupWebApiKey = _appSettings.MeetupWebApiKey;
        ...
    }
    
    ...
}

Azure Application Settings

Just now Secret Manager tool has helped us on managing the app secrets in local development environment. How about when we deploy our web app to Microsoft Azure?

For dotnet.sg, I am hosting the website with Azure App Service. What so great about Azure App Service is that there is one thing called Application Settings.

Screen Shot 2017-01-29 at 11.19.42 PM.png

Application Settings option is available in Azure App Service.

For .NET applications, the settings in the “App Settings” will be injected into the AppSettings at runtime and override existing settings. Thus, even though I have empty strings in appsettings.json file in the project, as long as the correct values are stored in App Settings, there is no need to worry.

Thus, when we deploy web app to Azure App Service, we should never put our app secrets, connection strings in our .config and .json files or even worse, hardcode them.

Application Settings and Timezone

Oh ya, one more cool feature in App Settings that was introduced in 2015 is that we can change the server time zone for web app hosted on Azure App Service easily by just having a new entry as follows in the App Settings.

WEBSITE_TIME_ZONE            Singapore Standard Time

The setting above will change the server time zone to use Singapore local time. So DateTime.Now will return the current local time in Singapore.

References

If you would like to read more about the topics above, please refer to following websites.

Advertisements

Deploy ASP .NET Core Directly via Git

secret-manager-tool-azure-app-service-2

You can deploy ASP .NET Core web apps to Azure App Service directly using Git.

This is actually part of the Continuous Deployment workflow for apps in Azure App Service. Currently, Azure App Service integrate with not only Github, but also Visual Studio Team Services, BitBucket, Dropbox, OneDrive, and so on.

screen-shot-2017-01-30-at-1-14-16-pm

Available deployment source options in Azure App Service.

Although dotnet.sg source code is on Github, choosing the “GitHub” option cannot detect its repository. This is because the Github option only lists the repositories on my personal Github account. The dotnet.sg repo whereas is under the sg-dotnet Github Organization account. Hence, I have to choose “External Repository” as the deployment source instead.

Screen Shot 2017-01-30 at 1.21.03 PM.png

Setting up External Repository (Git) as deployment source in Azure App Service.

After that, whenever there is a new commit, if we do “Sync”, it will create a new deployment record, as shown in the screenshot below. We can anytime revert back to the previous deployment by right-clicking on the desired deployment record and select “Redeploy”.

Screen Shot 2017-01-30 at 1.13.35 PM.png

Deployment history in Azure App Service.

Kudu

So what if we want to customize the deployment process?

Before going into that, the first thing we need to say hi to is Kudu. What is Kudu? Kudu is the engine behind Git deployment in Azure App Service. It is also a set of troubleshooting and analysis tools for use with Azure App Service. It can capture hang dump for worker process for performance analyzing purposes.

On Kudu, we can also download the deployment script, deploy.cmd. We can then edit the file with any custom step we have and put the file under the root of repository.

There is another simpler way which is using a file with the filename “.deployment” at the root of repository. Then in the content of the file, we can specify our command to run during deployment as follows.

[config]
command = THE COMMAND TO RUN FOR DEPLOYMENT

To learn more about Kudu, please watch the following video clip from Channel 9.

References

If you would like to read more about the topics above, please refer to following websites.

Front-end Development in dotnet.sg

yeoman-bower-npm-gulp

The web development team in my office at Changi Airport is a rather small team. We have one designer, one UI/UX expert, and one front-end developer. Sometimes, when there are many projects happening at the same time, I will also work on the front-end tasks with the front-end developer.

In the dotnet.sg project, I have chance to work on front-end part too. Well, currently I am the only one who actively contribute to the dotnet.sg website anyway. =)

Screen Shot 2017-01-29 at 12.49.23 AM.png

Official website for Singapore .NET Developers Community: http://dotnet.sg

Tools

Unlike the projects I have in work, dotnet.sg project allows me to choose to work with tools that I’d like to explore and tools that helps me work more efficiently. Currently, for the front-end of dotnet.sg, I am using the following tools, i.e.

  • npm;
  • Yeoman;
  • Bower;
  • Gulp.

Getting Started

I am building the dotnet.sg website, which is an ASP .NET Core web app, on Mac with Visual Studio Code. Hence, before I work on the project, I have to download NodeJs to get npm. The npm is a package manager that helps to install tools like Yeoman, Bower, and Gulp.

After these tools are installed, I proceed to get a started template for my ASP .NET Core web app using Yeoman. Bower will then follow up immediately to install the required dependencies in the web project.

screen-shot-2017-01-28-at-9-03-10-pm

Starting a new ASP .NET Core project with Yeoman and Bower.

From Bower with bower.json…

Working on the dotnet.sg project helps me to explore more. Bower is one of the new things that I learnt in this project.

To develop a website, I normally make use of several common JS and CSS libraries, such as jQuery, jQuery UI, Bootstrap, Font Awesome, and so on. With so many libraries to manage, things could be quite messed up. This is where Bower comes to help.

Bower helps me to manage the 3rd party resources, such as Javascript libraries and frameworks, without the need to locate the script files for each resources myself.

For example, we can do a search of a library we want to use using Bower.

Screen Shot 2017-01-28 at 9.44.47 PM.png

Search the Font Awesome library in Bower.

To install the library, for example Font Awesome in this case, then with just one command, we can easily do it.

$ bower install fontawesome

The libraries will be installed in the directory as specified in the Bower Configuration file, .bowerrc. By default, the libraries will be located at the lib folder in wwwroot.

screen-shot-2017-01-28-at-10-08-44-pm

Downloaded libraries will be kept in wwwroot/lib as specified in .bowerrc.

Finally, to check the available versions of a library, simply use the following command to find out more about the library.

$ bower info fontawesome

I like Bower because checking bower.json into the source control ensures that every developer in the team has exactly the same code. On top of that, Bower also allows us to lock the libraries to a specific version. This will thus prevent some developers to download some different version of the same library from different sources themselves.

…to npm with package.json

So, now some of you may wonder, why are we using Bower when we have npm?

Currently, there are also developers supporting the act to stop using Bower and switch to npm. Libraries such as jQuery, jQuery UI, and Font Awesome, can be found on npm too. So, why do I still talk about Bower so much?

For ASP .NET Core project, I face a problem on referring to node_module from the View. Similar as Bower, npm will position the downloaded packages in a local folder also. The folder turns out to be node_module, which is on the same level as wwwroot folder in the project directory.

As ASP .NET Core serves the CSS, JS, and other static files from the wwwroot folder which doesn’t have node_module in it, the libraries downloaded from npm cannot be loaded. One way will be using Gulp Task but that one is too troublesome for my projects so I choose not to go that way.

Please share with me how to do it with npm in an easier way than with Bower, if you know any. Thanks!

Goodbye, Gulp

I first learnt Gulp was when Riza introduced it one year ago in .NET Developers Community Singapore meetup. He was then talking about the tooling in ASP .NET Core 1.0 projects.

However, about four months after the meetup, I came to a video on Channel9 announcing that the team removed Gulp from the default ASP .NET template. I’m okay with this change because using BundleMinifier to do bundling and minifying of CSS and JS now without using Gulp because using bundleconfig.json in BundleMinifier seems to be straightforward.

However, the SCSS compilation is something I don’t know how to do it without using Gulp (Please tell me if you know a better way. Thanks!).

To add back Gulp to my ASP .NET Core project, I do the following four steps.

  1. Create a package.json with only the two compulsory properties, i.e. name and version (Do this step only when package.json does not exist in the project directory);
  2. $ npm install --save-dev gulp
  3. $ npm install --save-dev gulp-sass
  4. Setup the generated gulp.js file as shown below.
var gulp = require('gulp');
var sass = require('gulp-sass');

gulp.task('compile-scss', function(){
    gulp.src('wwwroot/sass/**/*.scss')
        .pipe(sass().on('error', sass.logError))
        .pipe(gulp.dest('wwwroot/css/'));
})

//Watch task
gulp.task('default', function() {
    gulp.watch('wwwroot/sass/**/*.scss', ['compile-scss']);
})

After that, I just need to execute the following command to run gulp and changes made to the .scss files in the sass directory will trigger the Gulp Task to compile the SCSS to corresponding CSS.

$ gulp

There is also a very detailed online tutorial written by Ryan Christiani, the Head Instructor and Development Lead at HackerYou, explaining each step above.

Oh ya, in case you are wondering what is the difference between –save and –save-dev in the npm commands above, I like how it is summarized on Stack Overflow by Tuong Le, as shown below.

  • –save-dev is used to save the package for development purpose. Example: unit tests, minification.
  • –save is used to save the package required for the application to run.

Conclusion

I once heard people saying that web developers were the cheap labour in software development industry because they are still having the mindset that web developers just plug-and-play modules on WordPress.

After working on the dotnet.sg project and helping out in front-end development at work, I realize that web development is not an easy plug-and-play job at all.

Picking Up SCSS

sass-web-compiler-visual-studio-pluralsight

Last week, during our work discussion, we came to this point where we argued if “fast first, slow later” or “slow first, fast later” is suitable in our working environment.

In startup mode, everything comes at you quickly, and you tend to react fast. So in the first two years of setting up the Innovation Team in Changi Airport, our software development team had been working very hard and very fast to meet the deadline. Now, our company is switching from startup mode to scale-up mode where we need to shift towards doing things right more often than doing things fast.

Hence, we are working on setting up a set of suitable development and design principles in our development team. Applying SCSS to refactor our CSS is part of this time-consuming, difficult, and tiring process.

Installing Web Debugger in VS2015

After the introduce of Web Essentials 2015, features such as compiling SCSS files have been moved to another extension called Web Compiler in Visual Studio.

Hence, to get started in VS2015, we need to first download Web Compiler via Tools > Extensions and Updates.

Installing Extensions in VS2015.png

Installed Web Compiler in Visual Studio 2015

We will need to restart Visual Studio after the installation. Once the Visual Studio is restarted, we then can start using SCSS in our web projects.

By using Web Compiler, every time we save the .scss file, it will auto compile it to be a corresponding .css file (with minified version as well!).

Another feature that I like in this extension is that Visual Studio will specify whether the SCSS files are “Compiled successfully” or there is any SCSS error, as shown in the screenshot below.

SCSS Error Reporting in VS2015.png

Visual Studio will provide friendly error messages for SCSS too!

Refactor CSS into SCSS

Previously, besides using CSS from Bootstrap, we mostly handcrafted our CSS. Recently, it had become quite hard to maintain. So I started to refactor the CSS files from one of our web projects into SCSS.

Firstly, I created a new set of blank SCSS files while keeping the existing CSS files untouched. Secondly, I change the CSS reference of the website to use the new CSS files generated by the Sass pre-compiler. By doing this, I can choose to slowly refactor the existing CSS.

Change I Love #1: Introduction of Variables

Taking just brand colour as an example, currently our CSS files have it all over the place. The same shade of blue appears a lot of times. It is incredibly hard and time consuming to make changes in our web projects using plain CSS.

Previously, for example, we have the following CSS.

.btn-main {
    background-color: #28c8f0;
    border-color: #28c8f0;
}

The primary colour #28c8f0 is used in other classes throughout the whole CSS. Hence, we can just define it as a variable $primary-color: #28c8f0; and then use it

.btn-main {
    background-color: $primary-color;
    border-color: $primary-color;
}

In the future, if we want to change the primary colour to another colour, we just need to change it at one place without worrying if we miss out any part of the CSS not updated.

Change I Love #2: DRY with Mixin

Don’t Repeat Yourself (DRY), if we are using plain CSS, we normally find ourselves reusing the same set of codes throughout the CSS files. So, by using mixins in SCSS, there will always be one and only one set we need to remember and reuse.

Before using SCSS:

.customized-width-250 {
    margin-top: 4px;
    border: 1px solid #ffffff;
    border-radius: 5px 5px 5px 5px;
    font-weight: bold;
    height: 30px;
    min-width: 250px; 
}

.customized-width-120 {
    margin-top: 4px;
    border: 1px solid #ffffff;
    border-radius: 5px 5px 5px 5px;
    font-weight: bold;
    height: 30px;
    min-width: 120px; 
}

.customized-width-60 {
    margin-top: 4px;
    border: 1px solid #ffffff;
    border-radius: 5px 5px 5px 5px;
    font-weight: bold;
    height: 30px;
    min-width: 60px; 
}

Now, by using mixin, we can easily remove the duplicates for easy maintenance.

@mixin customized-controls ($width) {
    margin-top: 4px; 
    border: 1px solid #ffffff; 
    border-radius: 5px 5px 5px 5px; 
    font-weight: bold; 
    height: 30px;
    min-width: $width;
}

.customized-width-250 {
    @include customized-controls(250px);
}

.customized-width-120 {
    @include customized-controls(120px);
}

.customized-width-60 {
    @include customized-controls(60px);
}

Change I Love #3: Loops and Conditional

On our website, we need to display representative image for each of the countries available on the portal.

If we are using plain CSS, we need to do the following for each country. For example, for Australia, we have the follows.

.country-box-australia {
    background-image: url("/images/device-country-australia.png");
}

Now we have 9 countries on our portal. So we need to repeat the lines above for 9 times. If the images are moved to another folder, then we need to update the CSS at 9 places.

In SCSS, we can use list and each loop to make the CSS more readable.

$portal-countries: australia, france, hong-kong, japan, malaysia, new-zealand, south-korea, taiwan, thailand;

@each $country in $portal-countries {
    .country-box-#{$country} {
        background-image: url('/images/device-country-#{$country}.png')
    }
}

As you see above, it also makes use of Interpolation #{} to make the code even cleaner.

Change I Love #4: Color Functions

This is helpful especially when we do the hover effect for buttons. Previously, we always needed to ask the Design Team to give us two colour codes for buttons. One for non-hover and one for hover.

So with the Color Functions in SCSS, we can now do as follows.

a {
    text-decoration: none;
    color: $primary-color;

    &:hover, &:focus {
        text-decoration: none;
        color: darken($primary-color, 20%);
    }
}

We then can have a consistent look-and-feel throughout the whole website.

Oh ya, the & character above is used to reference parent selector.

Change I Love #5: Partials

We can also have partials by starting the name of the partials with an underscore.

Because of partials, we can organize our SCSS files properly according to their functionality.

Conclusion

I believe that now given the fact that our company is already in a scale-up mode, if we keep doing everything in a hacking way, we will easily end up with technical debt soon. Having technical debt means that we will need to spend extra development work in the future because the best overall solution is not implemented in the beginning.

That is why I always welcome opportunities to learn and improve my skills. This includes learning from my teammates via our countless conversations because the conversations kept me inspired and kept me going. The team had made me a better developer. Picking up SCSS is one of the examples and it is only the beginning.

Learning Materials

Exploring Azure Search

azure-search-meetup.png

Last year, Riza shared about his small little algorithm to do smart auto complete in WPF in Singapore .NET Developers Community March meetup. Riza has his project for this, SmartSuggestions, available on Github. What it does is that it will prompt user for smart suggestion of typos and find the similar words for suggestion.

meetup-riza-smart-suggestion

Riza Marhaban is sharing his SmartSuggestion algorithm to the audience during the community meetup. (Photo Credit: Singapore .NET Developers Community)

I find his program to be very interesting. In fact, I did a similar task when I was working in Easibook as well. By calculating the Levenshtein Distance of user input and the records in database, the small JavaScript code I wrote is able to suggest the places even user keys in the place name wrongly.

Soon after Riza’s talk about his SmartSuggestion, I read the announcement of general availability of Azure Search from Microsoft team.

azure-search-generally-available

Azure Search is generally available!

Azure Search

Azure Search is a fully managed search-as-a-service in Microsoft Azure. It offers scalable full-text search for the program. Hence, with its help, developers do not need to re-invent the text-searching capability in their programs and websites.

Azure Search currently provides two ways of querying text. One is using Simple Query Syntax where user can do keywords searching, phrase searching, suffix searching, etc. AND/OR/NOT operator is also available for use.

Another way of querying will be Lucene Query Parser. What interests me the most in Lucene Query Syntax is the use of Damerau–Levenshtein Distance in its Fuzzy Search, which does more than the Levenshtein Distance that only allows insertion, deletion, and substitution operations.

Try It Out!

In order to try out this feature, I have decided to create a demo program to test its functionality.

In this program, I use the event data from the .NET Developers Community Singapore to demonstrate how Azure Search works. To do this, I have to integrate with the Meetup APIs in this program.

Currently, this demo application covers the following features in Azure Search.

  • Create Azure Search index;
  • Data upload;
  • Keywords query in both Simple Query Syntax and Lucene Query Syntax.

Here are some of the screenshots of querying using Azure Search.

For example, if I’d like to find out what the talks covering topic about Visual Studio are, I can just simply search by “visual studio” as a phrase, as shown in the following screenshot.

azure-search-phrase-search

Phrase Searching in Azure Search

Or let’s say a user wants to search the meetup events about “Xamarin” but he doesn’t know its correct spelling is either Xamarin or Zamarin. So he can do a Fuzzy Search by keying in “Zamarin~”. Take note of the tilde “~” symbol at the end of the word. It means the search of the word will be done using Fuzzy Search.

azure-search-fuzzy-search

Fuzzy Search in Azure Search

Holiday and Coding

Christmas is a public holiday in Singapore. Since Christmas is on Sunday, I get a day off on Monday. So besides taking a rest in my room, I did a quick research on Azure Search. It’s kind of fun because it helps me to learn new things which I don’t have chance to explore during work.

search-with-ease.png

With Azure Search, we can now search with our minds at east. (Image Credit: Re:Zero Kara Hajimeru Isekai Seikatsu, KissAnime)

Anyway, I have uploaded my demo program project to Github. Feel free to check it out!

github-azure-search-demo

Burger and Cheese

xamarin-cognitive-services-android-voicetext

As a web developer, I don’t have many chances to play with mobile app projects. So rather than limit myself to just one field, I love to explore other technologies, especially mobile app development.

Burger Project: My First Xamarin App

Last month, I attended a Xamarin talk at Microsoft Singapore office with my colleague. The talk was about authentication and authorization with social networks such as Facebook and Twitter via Azure App Service: Mobile App.

Ben Ishiyama-Levy is talking about how Xamarin and Microsoft Azure works together.

Ben Ishiyama-Levy is talking about how Xamarin and Microsoft Azure works together.

The speaker is Ben Ishiyama-Levy, a Xamarin evangelist. His talk inspired me to further explore how I could retrieve user info from social network after authenticating the users.

Because I am geek-first and I really want to find out more, so I continue to read more about this topic. With the help from my colleague, I developed a simple Xamarin.Android app to demonstrate the Authentication and logged-in user’s info retrieval.

The demo app is called Burger and it can be found on my Github repository: https://github.com/goh-chunlin/Burger.

Challenges in Burger Project

Retrieving user's info from social network.

Retrieving user’s info from social network.

In Burger project, the first big challenge is to understand how Azure App Service: Mobile App works in Xamarin. Luckily, with the material and tutorial given in the Xamarin talk from Ben, I was able to get a quick start on this.

My colleague also shared another tutorial which is about getting authenticated user’s personal details on Universal Windows Platform (UWP). It helps me a lot to understand about how mobile app and Azure App Service can work together.

My second challenge in this project is to understand Facebook Graph API. I still remember that I spent quite some time finding out why I could not retrieve the friend list of a logged-in Facebook user. With the introduction of the Facebook Graph API 2.0, access to a user’s friends list via /me/friends is limited to just friends using the same app. Hence after reading a few other online tutorials, I finally somehow able to get another subset of a user’s friends via /me/taggable_friends.

In this project, it’s also the first time I apply Reflection in my personal project. It helps me easily get the according social network login class with a neat and organized code.

microsoftdeveloperday

Microsoft Developer Day at NUS, Singapore in May 2016

Cheese Project: When Google Speech Meets MS LUIS on Android

Few months ago, I’m fortunate to represent my company to attend Microsoft Developer Day 2016 in National University of Singapore (NUS).

The day is the first time Microsoft CEO Satya Nadella comes to Singapore. It’s also my first time learn about the powerful Cognitive Services and LUIS (Language Understanding Intelligence Service) in Microsoft Azure in Riza’s talk.

presentation

Riza’s presentation about Microsoft Cognitive APIs during Microsoft Developer Day.

Challenges in Cheese Project

Everyday, it takes about one hour for me to reach home from office. Hence, I will only have two to three hours every night to work on personal projects and learning. During weekends, when people are having fun out there, I will spend time on researching about some exciting new technologies.

There are many advance topics in LUIS. I still remember that when I was learning how LUIS works, my friend was actually playing the Rise of the Tomb Raider beside me. So while he was there phew-phew-phew, I was doing data training on LUIS web interface.

luis

Microsoft LUIS (Language Understanding Intelligence Service) and Intents

Currently, I only worked on some simple intents, such as returning me current date and time as well as understanding which language I want to translate to.

My first idea in Cheese project is to build an Android app such that if I say “Please translate blah-blah to xxx language”, the app will understand and do the translation accordingly. This can be quite easily done with the help of both LUIS and Google Translate.

After showing this app to my colleagues, we realized one problem in the app. It’s too troublesome for users to keep saying “Please translate blah-blah to xxx language” every time they need to translate something. Hence, recently I have changed it to use GUI to provide language selection. This, however, reduces the role played by LUIS in this project.

voicetext

VoiceText provides a range of speakers and voices with emotions!

To make the project even more fun, I implemented the VoiceText Web API from Japanese in the Android app. The cool thing about this TTS (Text-To-Speech) API is that it allows developers to specify the mood and characteristic of the voice. The challenge, of course, is to read the API written in Japanese. =P

Oh ya, this is the link to my Cheese repository on Github: https://github.com/goh-chunlin/Cheese. I will continue to work on this project while exploring more about LUIS. Stay tuned.

languagelist    googlespeech    SuccessfullyTranslated.png

After-Work Personal Projects

There are still more things in mobile app development for me to learn. Even though most of the time I feel exhausted after long work day, working on new and exciting technologies helps me getting energized again in the evening.

I’m not as hardworking as my friends who are willing to sacrifice their sleep for their hobby projects and learning, hence the progress of my personal project development is kind of slow. Oh well, at least now I have my little app to help me talking to people when I travel to Hong Kong and Japan next year!

Growth Hacker: Hybrid of Marketer and Programmer

Growth Hacker Marketing and Growth Hacking Handbook

I don’t know why people like to call software developers as hackers. Even though calling them hackers is way better than using other names like ninjas or code monkeys, I think it’s still not appropriate to call developers hackers. So, I find it quite weird when I met someone who is Growth Hacker. Err… Hack what?

Growth Hacker

Andrew Chen, an investor for tech startups, describes growth hacker as

a hybrid of marketer and coder, one who looks at the traditional question of “How do I get customers for my product?” and answers with A/B tests, landing pages, viral factor, email deliverability, and Open Graph.

A growth hacker is someone who has thrown out the playbook of traditional marketing and replaced it with only what is testable, trackable, and scalable. Their tools are e-mails, pay-per-click ads, blogs, and platform APIs instead of commercials, publicity, and money.
(Holiday, Ryan. 2013. Growth Hacker Marketing. New York : Penguin Group, 2013)

Hence, growth hacker plays an important role in startup or SME which has little to no resources. Growth hacker needs to make use of their programming skills to provide more scientifically way of understanding who customers are and where they are.

Developer + Marketer = Growth Hacker

Developer + Marketer = Growth Hacker

Growth hacking highlights the importance of Product Market Fit. Instead of expecting marketers to show a product that nobody wants, company with growth hacking mindset will now spend time on trying different way of improving product based on customer feedback.

Growth hacker tests the ideas by letting customers to try our different version of the product and then ask the customers what they like about the product. One way to receive feedback is by looking at conversion rate or by the number of Facebook likes received. Hence, this helps the company to publish a product which is worth marketing and has majority of its customers love to use.

Different Stages in Growth Hacking

I’m glad to have talked to people who are experienced in growth hacking. They recommended me two books to read. One is the Growth Hacker Marketing by Ryan Holiday.

In Ryan Holiday’s book, growth hacking basically has 3 stages as follows.

  1. Finding your growth hack;
  2. Going viral;
  3. Closing the loop: Retention and optimization.
3 stages in Growth Hacker Marketing.

3 stages in Growth Hacker Marketing.

Growth Hacking Tactics

Another book which is recommended to me to read is Growth Hacking Handbook written by Jon Yongfook. The book suggested 100 growth tactics which many startups have successfully applied over the last 2 decades.

I am not going to list all the 100 items here. So, I will just highlight some of them which I find to be interesting.

Tactic 01: The We Can’t Go Back Jack Hack

On the signup page or checkout page, disable or remove all navigational elements that would enable a user to go back to the previous page. This includes disabling your site logo, which is often linked to the homepage.

The reason of having this tactic is because preventing users from leaving a process is sometimes good enough to force them to complete the entire signup/booking process.

In the Amazon checkout page, user can't go back to the homepage by clicking on the logo.

In the Amazon checkout page, user can’t go back to the homepage by clicking on the logo. Instead they have to click on the tiny link at the bottom.

I don’t really like this idea because it’s sort of locking customers in your shop and then telling the customers that they can’t leave your shop until they make the payment. It creates a bad user experience.

Growth Hacking: Shut the door, release the dog and then lock the customers in our shop!

Growth Hacking: Shut the door, release the dog and then lock the customers in our shop!

Tactic 02: The Pre-filled Form Hack

Instead of forcing customers to buy our goods before leaving our shop, why don’t we just create a fast signup/checkout process?

One way of doing that is to make the form short and pre-fill form fields with information if we already have it, such as customer’s email address.

For example the checkout form below will scare customers away not because it’s too long but it also requests too much personal information from the customers without giving any explanation why the information is needed.

Booking ferry tickets from Singapore to Batam on Easybook requires you to enter every single passenger's name, gender, DOB, nationality, passport, and passport expiry date. On top of that, the system also requires you to manually specify the number of adults and children even though DOB of each passenger is already given.

Booking ferry tickets from Singapore to Batam on Easybook requires you to enter every single passenger’s name, gender, DOB, nationality, passport, and passport expiry date. On top of that, the system also requires you to manually specify the number of adults and children even though DOB of each passenger is already given.

Tactic 03: The As Seen On TV Hack

Users feel more comfortable when they know the products they are using now are something that other famous people have already used it. So having logos of media outlets who have mentioned about our product on our homepage is another form of social proof.

Drive.SG is using the As-Seen-On hack.

Drive.SG is using the As-Seen-On hack.

Tactic 04: The Multi Post Hack

This tactic is also quite straightforward. It basically means giving the option to post the website content to other social networks with just one click. That will help to push our product to a wider network via social networks.

Tactic 05: The Timebomb Hack

This is a pressure tactic where a time limit is set when a user is making critical decision such as a purchase. I don’t like to use this tactic in my ecommerce website because as a consumer, I prefer to choose what to buy without any pressure. I normally just quit the website when it forces me to finish a task in a very little time.

Customers needs to complete their transaction within 5 minutes on CurrencyBooking, a money changing platform.

Customers needs to complete their transaction within 5 minutes on CurrencyBooking, a money changing platform.

Tactic 06: The Winback Hack and the Negative Follow Up Hack

These two tactics are quite similar. The goal is to get feedback from users who are inactive and having incomplete transactions and incentivize them to return to the website.

A simple winback campaign can be automatically sending highly personalized email to those users who have not logged in for past 30 days. Normally, a winback campaign is our last chance at communicating with our users before they unsubscribe from us.

Sending email to customers who have signed up but do not buy any of our product is also important. That will help us to better understand why some customers do not want to buy from us (and sometimes it could be because of having bugs in the payment module).

The following is an email I received after subscribing an online service.

Hi Chun Lin,

I noticed you recently added our product to your cart but did not submit the order – wondering if you have any questions about our platform or pricing?

We’re always here to help so please do not hesitate to contact me! You can find my contact info, including my direct number, in the email signature below.

Direct number and contact info! Wow!

I don’t sign up with them in the end because I don’t really need their product at that moment. However, I’m still very impressed by their friendly email.

Tactic 07: The Intro Video Hack

If a picture is worth a thousand words, then a video is worth a million. Most people will find video content more interesting than standard text content. Hence, video content is useful to attract a significant number of inbound links and social shares for our website.

Recently, Google Search results page also displays Rich Snippet which contains information about the video embedded on the page. Hence, the Rich Snippet helps our web page to stand out from the other search results on the page. Therefore, users will be more inclined to click on the link pointing to our website.

Tactic 08: The Register to Save Hack

Instead of getting users to sign up first, we can choose to only ask users for their email after they have gone through some steps. This is to encourage users to try our product first to understand about the product better so that the eventual conversion to signup is easy.

Singapore Real Estate Exchange allows users to freely search, then requires login/signup when users want to shortlist the property.

Singapore Real Estate Exchange allows users to freely search, then requires login/signup when users want to shortlist the property.

Tactic 09: The Widget Hack and The Affiliate Program Hack

Instead of asking users to share our website via a link in text, why not giving them an embeddable widget to our product which can be easily added to any other website or blog? Then from there we can get those who embed our widget on their websites/blogs to participate in our affiliate program so that people are motivated to refer customers to our website.

Bus ticket search widget from BusOnlineTicket.com Affiliate Program.

Bus ticket search widget from BusOnlineTicket.com Affiliate Program.

Tactic 10: The Remarketing Tag Hack

Nowadays, on Facebook, there is an option to create Custom Audiences from our website which enable us to target our Facebook Adverts to only those who have visited our website. Alternatively, it also allows excluding existing customers so that we can focus on new customer acquisition campaigns.