Common Web App Mistakes from an Architecture Perspective

Introduction

I recently inherited an AngularJS web front-end that is part of a larger 2 year development project, and essentially the only message I was given by the project manager was this: "we are going live in two weeks, and we have issues".

From a functional perspective the app was complete, but there were a few bugs that we had to resolve before go-live. From a technical perspective, there were a few issues that made maintenance of this application particularly difficult and turnaround time quite slow. In this post I will highlight these technical concerns and how I went about resolving the issues.

Some of the bugs that needed fixing had to do with a bad user experience, and were indicative of underlying technical issues. The issues I want to address in this post, however, are more from the perspective of a software architect, and is probably something any developer can relate with.

No README

The original developer on the project was a contractor who wasn't renewed when his time ran out. It turns out there wasn't even time for him to jot down a few notes in the auto-generated .README in GitHub.

The main source of truth I had to go by was the package.json and Gruntfile.js - most of what I needed to know was in these files (thank goodness). Eventually I was able to get more knowledge from the original software architect (I figured out who he was by looking at the commit history - it turns out he created the project about 2 years ago using Yeoman).

Outdated Dependencies

During each CI build, Node would print warnings that there are numerous deprecated dependencies that desperately need updating. Unfortunately, with only 2 weeks until go-live and a number of bugs to fix, it was not a good time to update the outdated dependencies.

The lesson is that is important to always try to keep your dependencies up to date while you're in development, and only to lock the versions down towards the end of the project.

Continuous Integration Done For the Sake of Having It

The project made use of Continuous Integration (Travis CI, which has many benefits.

The biggest concern I had was that every build spanned 13-14 minutes - I'm not exaggerating. Now this would be OK if it was a really big project with dozens of dependencies (and even then there would be more efficient ways to handle that), but this project was nowhere near that. When I received it, the project had about 40-50 dependencies in the package.json file, and judging by the scope I just couldn't believe that all of them were necessary (sure, some of them were only devDependencies, but still).

The first thing I did to figure out what dependencies were used, was to run depcheck. Less than 10 dependencies were flagged as being used, so I immediately proceeded to remove the rest. That might have been a little drastic (I didn't configure depcheck properly), but every grunt build told me exactly which dependency was missing. So, one by one I re-added the required ones, and ultimately the application only had about 30 dependencies - much less to install during CI.

At this point I was curious to see if the build would be faster, and to my dismay it still took more than 10 minutes. It was clear that I needed to investigate the problem a bit further. The previous developer, it turns out, couldn't get the node modules installed using the travis.yml, so resorted to a shell script to install each dependency. What this meant was that every time a dependency needed to be added or removed from the project, it had to be done in the package.json and in the the shell script file. When I fixed this issue with a small change to the travis.yml file, lo and behold, the build time was only 3 and a half minutes!

The main problem with CI implemented improperly is that it defeats one of the main benefits of using CI in the first place - it greatly hampers productivity. Can you imagine the amount of time the front-end developer waited for each deployment over a 2 year development cycle? (I should remember to check how many commits were made to GitHub so that I can calculate the amount of time waited - I'm sure the project manager will be in shock.)

Ignorance of .gitignore

Although this wasn't the biggest of problems, it was very confusing when I first started on the project (with no technical knowledge transfer as I mentioned above) to figure out what files and folders were used for local development, deployment to DEV and TEST, and ultimately PROD. I only later discovered the methodology behind it all was because Yeoman was used.

In this project there are three main folders: app, dev, and dist. app is where the actual changes should be made, dev is where the local development resources are deployed to, and dist is where the deployment artifacts are deployed to.

It is evident that the only folder that should really be in version control is the app folder. Thus, I deleted the dev folder, pushed the change to GitHub, added dev to .gitignore, and pushed it up as well. Initially, I did the same for dist, but it turned out that they are using a different branch to track releases, and because dist was in .gitignore, it wasn't moved into the deployment branch. Reluctantly (and pressured to fix the now non-functioning TEST environment), I had to remove dist from .gitignore. Hopefully I will get a chance to revisit this in the future.

In addition to the above, there was also a nodemodules and a bowercomponents folder. The nodemodules folder is obviously dependent on the package.json file, and is generated when running *npm install*. I proceeded to delete the nodemodules folder, push this change to GitHub, add a node_modules entry to .gitignore, and push this to version control too.

The bower_components folder is generated when the a bower command in the Gruntfile.js is executed. I definitely want to clean up this folder too, but for some reason it is not re-installed with each CI build, so it something I have to revisit.

Although it is not perfect yet, I nevertheless cleaned up the root folder in version control a little bit, and it will be easier for future developers to follow exactly what is going on.

No Source Maps

To my dismay, only the minified versions of all JavaScript and CSS files are deployed to DEV and TEST, making debugging extremely difficult. As a temporary workaround (because in such a short period of time I couldn't get the generated source maps to work properly), I deployed the raw files to DEV to be able to debug.

Conclusion

In this post I went over some of the issues I recently encountered with a project I inherited close to when it was supposed to be deployed to production - two weeks before go-live to be exact.

The changes I have made to enhance the developer's experience and improve maintenance of the project are highlighted in this post. I do realize it's only scratching the surface, but given the short time-frame, it was small changes for big wins.

In a subsequent post I might talk some of the common web development mistakes I've encountered in this project.


© 2017