During the process of rapid prototyping of web application, one issue kept coming up during meetings and discussions, and that is decision. Very often, these web app decisions are between short-term benefits versus long-term benefits.
External Authentication || In-house Authentication
For our project, we are using Facebook login to manage users. Users can perform various actions depending on their identity and roles, all linked to the app-scoped Facebook id and token. This seemed to work well for normal users, but what about admins? This is where decision has to be made:
Whether to use the same Facebook authentication and “tag” them as admins within our database, or create a separate authentication system for admins.
The advantage of using Facebook authentication system is obvious. It is simple. We already have the users in our database with Facebook id and token. All we need to do is add another column to mark the admin users. However, the drawback is also obvious. Using Facebook authentication ties our admin system with the external service Facebook. We cannot perform admin actions without Facebook authentication. Also, the role of normal user and admin user is mixed up in the same table, which is not a good design.
In contrast, if we build our own authentication system based on session or token, it would be the best practice for security but would take longer time.
For a 3-week project like ours, we want to build things fast. However, we also understand the importance of security and that is something we do not overlook. Hence, eventually we settled on something in-between. For the first layer of authentication, i.e. logging in, we use Facebook authentication. However, once the user logs in, we use our in-house authentication system based on tokens. The server would send the token to the front-end, and the front-end will use it in the Authorization
header of the subsequent HTTP request. In this way, we ensure our app’s API endpoints are secured. We also save time in implementing our own login system. In the future, it is also possible to switch Facebook login to a username+password based login system or other services without affecting the token-based API endpoints.
Config in Code || Config in Environment
This is also a common issue for web applications. Typically, there are 3 different environments that the app can run: local, staging and production. When using an external service like Facebook Graph API, it requires different app_id
for different domains. Hence, when issuing front-end AJAX requests, we need different app_id
for different environments.
For our project, we are using Angular.js to do client-side rendering. There are 3 main approaches to this problem.
The simple approach is to code the app_id
s within in the code. We can switch them depending on the environments by changing the source code. This is the easiest solution, but of course not elegant and do not scale well with increasing size of front-end codebase.
The alternative is to use 3rd party libraries such as grunt-ng-constant to manage config files independent of the codebase, so each environment will have its own copy of config files, independent of the code and not subjected to frequent changes.
The last approach uses the server. The front-end would first issue an HTTP request to the API endpoint to ask for the configurations. The server would reply depending on the different environments and the front-end then use the configurations to issue other requests. This approach delegates the task to the server, and has a bad consequence of adding an additional delay to all front-end requests that depends on the configurations.
We have been using the first and the most straight-forward solution for 2 weeks and now we have config variables across different places in the front-end. It is a tough decision at this point in time because to switch approach we need to do a lot of additional work and the actual time that we can enjoy the fruit of the approach is less than a week. Currently, we are still not decided on whether to switch or not. As more important tasks being assigned, it would probably be left as it is.
Nevertheless, given a fresh start at another 3-week project, I would have set up the second approach using external config files on day 1, because then it would make sense to invest a few hours and reap the fruit for a few weeks.
Lessons learnt
There are also other decisions we made everyday, and they all come back to the short-term vs long-term issue.
For a long-term solution:
Are we going to benefit from it for long enough to justify the efforts we put into it?
Although the timeline of the project is fixed at 3 weeks, that does not automatically mean we should choose short-term over long-term. For each decision, the short-term and long-term is relative.
For example, LESS/Sass vs CSS is a simple decision to make. It only takes less an hour to set up and teach other team members on how to use CCS preprocessors, but the time and efforts saved on customizing bootstrap and tweaking styles is huge. Hence it is almost always a good idea to use LESS/Sass over CSS. Unless of course your code is 3 lines of CSS .
Some decisions like LESS/Sass vs CSS are better made early because you can increase productivity immediately. However, we can delay decisions that are not so important to avoid the evil of premature optimization.
Regardless of the situation, we have to make sure that we make informed decisions. That is, the team has to do some research into the issue, find out different approaches and go through deliberations to examine the pros and cons of each approach before making the final call.
Cover photo from http://www.medicalnewstoday.com/articles/310140.php
Making the right decisions is important, hence this year we introduced the “justify your tech” milestone with the hopes that students do more thinking and make informed decisions from the start.
Putting config in your code is fine. I don’t see why it’s inelegant. It’s common to have a
config.dev.json
,config.staging.json
,config.prod.json
and the build step reads from the respective JSON files depending on the build env. Feel free to ping me if you want to discuss about this further (:What we are doing now is in Angular service:
// production
var app_id = 'a';
// staging
// var app_id = 'b';
// local
// var app_id = 'c';
Which is quite inelegant and takes up extra commits to change them.