You’ve inherited 100,000 lines of spaghetti code. Now what?

It’s the first day of your job at your startup as the new Angular developer on the block and you spend the first week warming up to the code base. On Friday your founder interrupts your morning coffee to say that he wants you to start working on updating an existing feature. You say “Sure! It’s about time I got my hands dirty”. You roll up your sleeves and get to work only to find:

  • Copy and pasted PHP code snippets in your Angular project
  • heavily using var instead of let or const
  • == instead of === almost everywhere you can find any object comparison
  • Each HTML and TypeScript file pushes ~1200 lines of code
  • Each route is it’s own component – there are no reusable components

And guess what! It’s all yours buddy. Don’t fret! Here’s what you should not do in this situation.

What you shouldn’t do

1. Don’t whine or complain

Do not set up a meeting with your boss and say “Hey this code base is horrible. We have to stop everything and re-do it all”. What are you expecting your founder to say to this? “Hey, wow bob, well…when you put it that way we should stop all product development and refactor the whole thing the way you want it”. Throwing your problems at your boss does not help the business. If you’re going to present a problem, present a solution or at least things you’ve tried. The business isn’t going to stop because you arrived.

2. Don’t be a cowboy

Your inner perfectionist is coming out now and you have the sudden urge to re-write the code base or at least most of it thinking you can do it better. Don’t. What is working now in production is working. There are many months, maybe even years of knowledge and experience behind that code block you just want to tear apart. Document the mysterious code blocks/components so that the next guy who looks at the code has some knowledge to work with. Refactoring the whole code base will be a drain of your company’s resources.

What you should do (from my experience)

1. Communicate constructively

Everything starts with solid communication. You should communicate with your direct report that the code is not in the best condition where you can just start pumping out features but that you’ll do your best to keep up with the deadlines. Don’t torture yourself by keeping the state of the project a secret and burn yourself out to meet a deadline to “just make it work” because you’re still warming up to the code base. This always leads to problems down the line. Work with your product manager to set appropriate deadlines. 

2. Start enforcing standards from day one

Do your best not to contribute to the spaghetti mess that you inherited. Start implementing some coding standards from day one and continue to enforce those standards. This will be very hard in the beginning, however, you will be very happy you did in a few months. You have to start somewhere right?

3. Understand your data services

I’ve found that the most effective way for me to start breaking up my Angular application in to components is to first understand the services that provide data to the components and make them accessible. When I start making my components, I try to make them as independent as possible from the other components. Understanding where your data is coming from and how to inject it properly in each component will help keep your components more independent, maintainable, and reusable.

3. Create your reusable components

Once you know where you data feeds are at, building reusable and maintainable components is a synch. In time you’ll see your code base come together and maybe you won’t be hating your work as much when sprints are easier to complete because you put the ground work to make reusable components.

Final notes

Refactor the code bit by bit on each deployment and soon you will be a much happier camper in about a month. Work hard but don’t forget to work smart. Please drop some comments below on how you guys have dealt with similar situations.

Simple Angular CI/CD pipeline with GitLab & AWS

In this tutorial, I will show you how to set up a simple CI/CD pipeline that compiles code on GitLab and then deploys to AWS EC2 via AWS CodeDeploy. This tutorial assumes:

  1. You have a working EC2 Ubuntu instance set up with a web server such as Nginx or Apache running and configured. 
  2. You have an existing code repository hosting an Angular project on GitLab.

Technologies Used: 

  • Angular 7
  • Gitlab CI/CD
  • AWS S3
  • AWS CodeDeploy
  • AWS EC2 Ubuntu 18.04 LTS

I’ve made a start project that I will be referencing throughout this project on Github will all the files you need already built in. Check it out here!

Step 1 – Create an S3 to AWS CodeDeploy Pipeline

I really don’t like dropping links in tutorials like this, however, for the sake of not re-writing Amazon’s documentation, I will have to tell you to follow all instructions in the tutorial in the link below. Only once you finished the tutorial will you be able to continue with the rest of this tutorial. Once you’re done with Amazon’s tutorial, you will have a CD pipeline ready to go waiting for GitLab to send the code.

https://docs.aws.amazon.com/codepipeline/latest/userguide/tutorials-simple-s3.html

If you have successfully completed the above tutorial, any changes pushed to your S3 bucket will be deployed immediately to your EC2 instance. Then steps below will show you how to upload your production bundle to S3 from Gitlab to complete the CI/CD pipeline.

Step 2 – Create an appspec.yml 

Welcome back! The first thing we’ll have to do is create an appspec.yml file in the src/ folder of our project. The appspec.yml will tell AWS CodeDeploy to deploy your code in a specific file directory on the server – in our case, it’s the /var/www/ directory. 

version: 0.0
os: linux
files:
  - source: ./
    destination: /var/www/

Then we have to tell angular to include this file as an asset so it stays preserved during the production build. To do this, we edit the assets block in our angular.json file to include "src/appspec.yml":

...
"tsConfig": "src/tsconfig.app.json",
            "assets": [
              "src/favicon.ico",
              "src/assets",
              "src/manifest.json",
              "src/appspec.yml"
            ],
            "styles": [
...

Step 3 – Create .gitlab-ci.yml

Gitlab offers a continuous integration service if you add a

.gitlab-ci.yml

file to the root directory fo your code repository. I’ve provided a sample .gitlab-ci.yml file as seen in example Github project. Please be sure to update the group name and repository name for your own project. If you copy this code please be sure to use your own repository name.

image: node:10

stages:
  - build
  - deploy

build:
  stage: 'build'
  script:
    - apt update
    - apt-get install -y nodejs
    - npm install -y npm@6.11.0
    - nodejs -v
    - npm -v
    - ls -la -F
    - npm ci
    - npx ng build --prod
  cache:
    paths:
      - node_modules/
  artifacts:
    when: on_success
    name: '$CI_JOB_NAME-$CI_COMMIT_REF_NAME'
    paths:
      - dist/angular-gitlab-ci-cd-example/
  only:
    - dev
    - master

deploy:
  stage: 'deploy'
  environment:
    name: production
  script:
    - apt update
    - apt install -y software-properties-common
    - apt install -y python-dev
    - apt install -y python-pip
    - pip install awscli
    - aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
    - aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
    - aws configure set region us-east-1
    - ls -la -F
    - mv dist/angular-gitlab-ci-cd-example/appspec.yml dist/
    - cd dist
    - ls -al -F
    - cd ..
    - aws deploy push --application-name angular-gitlab-ci-cd-example --s3-location $AWS_S3_LOCATION --ignore-hidden-files --source dist
  only:
    - master

If you commit to your master branch with this file in the root directory of your project, a CI pipeline will initiate with two steps outlined line-by-line below:

The Build Stage

1.Update the packages in the node:10 Docker container

- apt update

2. Install node & npm

- apt-get install -y nodejs
- npm install -y npm@6.11.0
- nodejs -v
- npm -v

3. Run npm install

- npm install

4. Build the production bundle of Angular using the local cli

- npx ng build --prod

6. Tell GitLab to cache your node_modules so that your project builds faster next time around

cache: 
    paths: 
      - node_modules/

7. This code block creates a build artifact that will be passed onto the next stage in the pipeline if all operations in the container run without error. In the case of Angular7, I’m passing the created dist/ directory to the next stage so that GitLab can send it to AWS to be deployed

  artifacts: 
    when: on_success    
    name: "$CI_JOB_NAME-$CI_COMMIT_REF_NAME"
    paths: 
      - dist/angular-gitlab-ci-cd-example/

8. This keyword tells GitLab only to run this stage when a commit is pushed to either the master and dev branches. You can customize any stage to run a specific set of branched or all branches if that’s what you need. 

  only:
    - dev
    - master

The Deploy Stage

1. Update the packages on the node:10 Docker image, install the python libraries needed for AWS CLI and then install the AWS CLI.

script: 
    - apt update
    - apt install -y software-properties-common
    - apt install -y python-dev  
    - apt install -y python-pip
    - pip install awscli

2. Navigate to your CI/CD settings in GitLab and add the following variables for your $AWS_ACCESS_KEY_ID and $AWS_SECRET_ACCESS_KEY from the CodeDeploy IAM User you created earlier from following the AWS tutorial in Step 1. You should also include the $AWS_S3_LOCATION as a CI/CD variable as well in the following format:

s3://your-bucket-name/your-bundle-name.zip

The <key> will be by the same name as the zip created from the build stage.

3. In this step, we are configuring the AWS CLI with the IAM Credentials of a user with the correct CodePipeline policies attached.

    - aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID
    - aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY
    - aws configure set region us-east-1

4. Remember from step 1 how we made sure the appspec.yml was preserved in the dist/ production bundle? Well, now we have to move it out it to the same directory level as the dist/ folder so that it sits on the same level as the dist/ folder. We have to do this to make the appspec.yml visible to AWS. If we do not do this, the AWS CLI will throw an error stating that it cannot find the appspec.yml file in the next step.

- mv dist/angular-gitlab-ci-cd-example/appspec.yml dist/
- cd dist
- cd .. 

5. Use the AWS CLI to deploy the dist/ bundle to AWS S3

 - aws deploy push --application-name angular-gitlab-ci-cd-example --s3-location $AWS_S3_LOCATION --ignore-hidden-files --source dist
only:
    - master

You’re Done!

Once you push your code to the master branch, navigate to the CI/CD pipeline and watch your code being built. Once GitLab is done building the production bundle, it will send it to AWS S3, which in turn will be deployed onto your live server moments later. I would love to hear your feedback on how I can improve this simple pipeline. 

Stuck on 92% Chunk Optimization on Angular Production Builds?

The purpose of this article is to show you how I overcame an out-of-memory issue while building the production version of my Angular web application on my Ubuntu server by adding swap space.

Please keep in mind that building the Angular production bundle using another cloud providers resources (like building Angular on an AWS EC2) can get expensive fast. In light of that I figured out a way to automatically build and deploy Angular production builds essentially for free on GitLab.

The Problem

While Angular CLI was building the production build on the server, the machine returned a process out of memory error message. Here is what the stack trace looked like on the terminal:


FATAL ERROR: Committing semi space failed. 
Allocation failed - process out of memory 
1: node::Abort() [ng build --prod --aot]

At the time of writing this post this was my technology stack:

• Ubuntu 16.04.5 LTS (xenial)
• Node 8.12.0
• Angular CLI 6.1.3
• Angular 6.1.2

The Solution

After some doing some online research I found that a solution to this problem was to add additional swap space on my server. In this post, I will show you how I added swap space to my Ubuntu 16.04.5 LTS.

What is Swap Space?

Swap space is essentially emergency RAM that that sits on your hard drive and is utilized whenever you’re running your RAM close to max capacity. Sometimes large programs make the entire system need extra memory. Swap space can be a dedicated partition of your hard drive, a swap file, or a combination of both. The steps below will show you how to add more swap space to your machine.

Click here for the Official Ubuntu Swap Faq

Checking System Swap Information

First, we will check out our system to see if there are any existing swap configurations with the following:

$ sudo swapon --show

If the machine does not return an output then your system does not swap space available.

You can verify that there is no active swap using the free utility:

$ free -h

If you see a row of 0B‘s in the Swap row, no swap is active on the system.

Check Available Hard Drive Space

The most common way of allocating space for swap is to use a separate partition devoted to the task. However, altering the partitioning scheme is not always possible. We can just as easily create a swap file that resides on an existing partition.

Before we do this, we should check the current disk usage by typing:

$ df -h

The device under /dev in the output is our disk in this case.

For machines with less than 1 GB, it is highly recommended that the swap space should be at bare minimum equal to the amount of RAM. On top of that, it’s also recommended that swap space is at maximum, twice the amount of RAM depending on the currently available disk space. If need more swap space than twice your RAM then you should upgrade your server or add more RAM.

Create a Swap File

Let’s create a file of the swap size that we want to be called swapfile in our root directory.

My server had 512MB of RAM so for this example I will create a 1GB file with fallocate. Please adjust the file size to meet the needs of your own server.

More information on fallocate

$ sudo fallocate -l 1G /swapfile

Once the swap file is created we can verify that the correct amount of space was allocated with the following command:

$ ls -lh /swapfile

output:

$ -rw-r--r-- 1 root root 1.0G Oct 02 12:15 /swapfile

Enabling the Swap File

With the swap file available we need to tell the machine to leverage the extra space available in the swap file. First, we need to set the swap file permissions to 600 to prevent other users from being from being able to access or modify the file.

$ sudo chmod 600 /swapfile

Format the file as swap with mkswap:

$ sudo mkswap /swapfile

More information on mkswap

output:

Setting up swapspace version 1, size = 1024 MiB (1073737728 bytes)
no label, UUID=41e86209-3802-424b-9a9d-d7683142dab7

After marking the file as swap space, we can enable the swap file allowing our system to start utilizing it:

sudo swapon /swapfile

We can verify that the swap space is available by typing:

$ sudo swapon --show

The terminal should return an output like the following:


NAME      TYPE  SIZE USED PRIO
/swapfile file 1024M   0B   -1

Enable the Swap File Permanently

If we reboot our server at the current moment, the machine won’t keep any of the changes we’ve made to the hard drive partition. To make the changes permanent we will have to copy our swap to the /etc/fstab.

$ sudo cp /etc/fstab /etc/fstab.bak

Last we must add the swap file details to /etc/fstab to make it available at boot up permanently.

echo '/swapfile none swap sw 0 0' | sudo tee -a /etc/fstab

Final Notes


Aside from this one case, there are many other reasons that one would need swap space which is included but not limited to memory consuming programs, hibernation (suspend-to-ask), unforeseeable circumstances, or optimizing memory usage. Please let me know if I could improve this post by making anything more clear!

Deploy an Angular App in Production with Nginx & Ubuntu on EC2

This purpose of this tutorial is to show you how to configure Nginx to serve an Angular app on AWS EC2. This tutorial assumes the following:

  • You already have an Amazon Web Services account (if not you can make one here) and have basic knowledge of security groups
  • You already have a purchased a domain name and have associated it with a publicly accessible IP address
  • You have an existing Angular Project hosted on a code repository (Github, GitLab, BitBucket, etc.) and have some basic knowledge of Angular

Summary of technologies used

  • Ubuntu 16.04 LTS
  • Nginx 1.10.3
  • AWS EC2
  • Angular 6.1.3

Step overview

  • Step 1 – Open an EC2 instance
  • Step 2 – Install packages and dependencies
  • Step 3 – Configure Nginx
  • Step 4 – Deployment

Step 1 – Open an EC2 instance

Log into your AWS account, navigate to the EC2 Dashboard, and select “Launch Instance”. From the list of AMIs select Ubuntu Server 16.04 LTS (HVM).

While setting up the instance, you will be brought to a page where you select the instance type. Select t2.micro (free tier eligible). Once selected, click “Review and Launch” at the bottom of the page. On the next page click “Launch” on the bottom of the page as well.

Once launched it will take a few minutes for AWS to boot up your very own EC2 instance. Store your generated key pair in a safe place on your local computer. (Here’s documentation from AWS on how to handle your key pair)

Note: You may have to adjust the security group on your EC2 instance so that your website is publicly available. There’s plenty of resources and stack overflow questions solving this potential issue.


Step 2 – Install packages and dependencies

Time to ssh into your Ubuntu server with:

ssh -i ~/path-to-your-key-pair ubuntu@ec2-your-public-ip.compute-1.amazonaws.com

Once you have successfully logged into your public server it’s time to install some packages. Execute these commands from within your Ubuntu machine:

# update Ubuntu's local package index 
$ sudo apt-get update 

# install git 
$ sudo apt-get install -y git 

# install Nginx 
$ sudo apt-get install -y nginx 

# clear out the local repository of retrieved package files 
$ sudo apt-get -s clean 

Step 3 – Configure Nginx

If you are new to Nginx I highly recommend reading the following to understand what these next steps actually do.

Common Pitfalls using Nginx

Nginx Quick Start

Nginx Configuration

Navigate the sites-available directory.

$ cd /etc/nginx/sites-available

and use your preferred editor (I use vim) to create a new file. In this case we’re storing our nginx configuration as example.com.

$ sudo vim example.com

Enter the following in your new file:

server {     
    listen 80;      
    listen [::]:80;            
    root /var/www/your-angular-app-name/dist;   
    server_tokens off;   
    index index.html index.htm;     
 
    location / {         
        # First attempt to server request as file, then         
        # as directory, then fall back to displaying a 404.          
        try_files $uri $uri/ /index.html =404;      
    } 
}

***The line root /var/www/your-angular-app-name/dist will tell Nginx where the index.html file is for your compiled Angular app.

Save your new file and symlink it to the sites-enabled folder.

$ cd /etc/nginx/sites-enabled 
$ sudo ln -s ../sites-available/example.com 
$ ls -l

Remove the default file that comes with Nginx in the sites-enabled directory. This default file was placed here by Nginx when it was installed.

$ sudo rm default

For good practice run a test on your Nginx configuration to correct any configuration or syntax errors (syntax always gets the best of us).

$ sudo nginx -t

• Restart Nginx:

$ sudo nginx -s reload

Step 4 – Deployment

Before deploying an angular application we must use the Angular CLI to create the production build that will be served on our EC2. You have the option of building the production bundle right on your local or on your live server. If you are working by yourself on a project, it’s okay to build and add the generated dist folder to git source control. Otherwise you should avoid adding the compiled dist bundle to git when working with others to avoid merge conflicts from everyone’s own build.

Angular CLI documentation on deployments

Below I will show you two ways to deploy your app. Both methods below are ok to “test the waters” to build small applications to understand how to deploy an Angular app but I don’t recommend you keep deploying Angular in the ways detailed below. It is well worth your time to learn how to build an automation pipeline that takes care of this process for you. See my article building a simple CI/CD pipeline from GitLab to AWS. (You can build and deploy your Angular app virtually free!)

Path 1: Building the production bundle locally

In the case that you are building the production build on your local you will need to run:

$ ng build --prod

If there are no errors when Angular is building the production bundle then a dist directory will be generated in the root directory (/) of your project.

Check in the new dist dist folder to source control so that you can pull it into your server.

You will then have to ssh into your EC2 and clone the git repository into the /var/www/ directory.

$ cd /var/www
var/www $ git clone https://your-project-name

Note: You may need to use the $ sudo flag if your user inside the server does not have the right permissions to run these commands.

Restart Nginx:

$ sudo nginx -s reload

Navigate to your URL or Elastic IP address and your site should be live! If all you see is an Nginx 404 page then double check the directory on the root ...; line in your Nginx sites-available file is pointing to the right directory.

Path 2: Building on the server

DISCLAIMER: Depending on how large your application is this following method can run up your cloud provider bill.

In the case that you are building the production build on your server, you will then have to ssh into your EC2 and clone the git repository into the /var/www/ directory:

$ cd /var/www
var/www $ git clone https://your-project-name

Note: You may need to use the $ sudo flag if your user inside the server does not have the right permissions to run these commands.

Now it’s time to create the production build right on the server by making sure you currently are in your source code directory. First we must install some additional dependencies on the EC2 instance with the following commands:

# install node package manager 
$ sudo apt-get install -y npm 

# install curl 
$ sudo apt-get install -y curl  
  
# install node.js $ curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash - 
 

# update node.js 
$ sudo apt-get install -y nodejs 
 
# install the Angular CLI 
$ sudo npm install -g @angular/cli  

Next we navigate to the directory where we cloned the repository

$ cd /var/www/the-project-you-just-cloned

Once in the project directory, you will run:

$ ng build --prod

If there is an issue with the production build then your website will display the generic Nginx 404 page. To avoid this I highly recommend testing the production build process by running the $ ng build --prod command on your local first for testing.

Once the dist folder has been built we will restart Nginx. Nginx has already been configured to look at the var/www/your-project/dist from our configuration above.

Restart Nginx:

$ sudo nginx -s reload

Navigate to your URL or Elastic IP address and your site should be live! If all you see is an Nginx 404 page then double check the directory on the root ...; line in your Nginx sites-available file is pointing to the right directory.


If you have this process down pat and want more of a challenge then check out my next post on building a simple CI/CD pipeline from GitLab to AWS.

How to preserve your static assets in the production bundle

If you want your static assets (images, svgs, etc.) to show up in production you’ll have to do the following:

  1. In your angular.json make sure that your assets folder holding your static assets is included in the assets block like so:
“tsconfig”:…
“assets”: [
  “src/favicon.ico”,
  “src/assets”,
  “src/robots.txt”,
  “src/sitemap.xml”
],
“styles”:…

With this addition to angular.json, you’re telling angular where to find the assets when you reference them throughout your code in the build process.

2. Make sure that you’re referencing the correct directory path to your assets in your HTML blocks. In the configuration above, each asset in the assets folder should be accessed like the following:

<img src="/assets/images/my_cool_image.jpg" /> 

Now when you build and deploy, the assets should show up because Angular knows where to find them now.

You’re done!

If you’ve followed all these steps, you’ll be able to navigate to your site domain in any browser and see your basic angular app up and running. If not, remember it can take up to 48 hours for any DNS changes to fully propagate if you’ve just associated your Elastic IP to your domain name manager! Thanks for reading!