Archive for February, 2016

Persisting Data Across Page Reloads: Cookies, IndexedDB and Everything In-Between

The following article is a guest post from Toptal. Toptal is an elite network of freelancers that enables businesses to connect with the top 3% of software engineers and designers in the world.

Suppose I’m visiting a web site. I right-click on one of the navigation links and select to open the link in a new window. What should happen? If I’m like most users, I expect the new page to have the same content as if I had clicked the link directly. The only difference should be that the page appears in a new window. But if your web site is a single-page application (SPA), you may see weird results unless you’ve carefully planned for this case.

Recall that in an SPA, a typical navigation link is often a fragment identifier, starting with a hash mark (#). Clicking the link directly does not reload the page, so all the data stored in JavaScript variables are retained. But if I open the link in a new tab or window, the browser does reload the page, reinitializing all the JavaScript variables. So any HTML elements bound to those variables will display differently, unless you’ve taken steps to preserve that data somehow.

Persisting Data Across Page Reloads: Cookies, IndexedDB and Everything In-Between

Persisting Data Across Page Reloads: Cookies, IndexedDB and Everything In-Between

There’s a similar issue if I explicitly reload the page, such as by hitting F5. You may think I shouldn’t ever need to hit F5, because you’ve set up a mechanism to push changes from the server automatically. But if I’m a typical user, you can bet I’m still going to reload the page. Maybe my browser seems to have repainted the screen incorrectly, or I just want to be certain I have the very latest stock quotes.

APIs May Be Stateless, Human Interaction Is Not

Unlike an internal request via a RESTful API, a human user’s interaction with a web site is not stateless. As a web user, I think of my visit to your site as a session, almost like a phone call. I expect the browser to remember data about my session, in the same way that when I call your sales or support line, I expect the representative to remember what was said earlier in the call.

An obvious example of session data is whether I’m logged in, and if so, as which user. Once I go through a login screen, I should be able to navigate freely through the user-specific pages of the site. If I open a link in a new tab or window and I’m presented with another login screen, that’s not very user friendly.

Another example is the contents of the shopping cart in an e-commerce site. If hitting F5 empties the shopping cart, users are likely to get upset.

In a traditional multi-page application written in PHP, session data would be stored in the $_SESSION superglobal array. But in an SPA, it needs to be somewhere on the client side. There are four main options for storing session data in an SPA:

  • Cookies
  • Fragment identifier
  • Web storage
  • IndexedDB

Four Kilobytes of Cookies

Cookies are an older form of web storage in the browser. They were originally intended to store data received from the server in one request and send it back to the server in subsequent requests. But from JavaScript, you can use cookies to store just about any kind of data, up to a size limit of 4 KB per cookie. AngularJS offers the ngCookies module for managing cookies. There is also a js-cookies package that provides similar functionality in any framework.

Keep in mind that any cookie you create will be sent to the server on every request, whether it’s a page reload or an Ajax request. But if the main session data you need to store is the access token for the logged-in user, you want this sent to the server on every request anyway. It’s natural to try to use this automatic cookie transmission as the standard means of specifying the access token for Ajax requests.

You may argue that using cookies in this manner is incompatible with RESTful architecture. But in this case it is just fine as each request via the API is still stateless, having some inputs and some outputs. It’s just that one of the inputs is being sent in a funny way, via a cookie. If you can arrange for the login API request to send the access token back in a cookie also, then your client side code hardly needs to deal with cookies at all. Again, it’s just another output from the request being returned in an unusual way.

Cookies offer one advantage over web storage. You can provide a “keep me logged in” checkbox on the login form. With the semantics, I expect if I leave it unchecked then I will remain logged in if I reload the page or open a link in a new tab or window, but I’m guaranteed to be logged out once I close the browser. This is an important safety feature if I’m using a shared computer. As we’ll see later, web storage does not support this behavior.

So how might this approach work in practice? Suppose you’re using LoopBack on the server side. You’ve defined a Person model, extending the built-in User model, adding the properties you want to maintain for each user. You’ve configured the Person model to be exposed over REST. Now you need to tweak server/server.js to achieve the desired cookie behavior. Below is server/server.js, starting from what was generated by slc loopback, with the marked changes:

var loopback = require('loopback');
var boot = require('loopback-boot');

var app = module.exports = loopback();

app.start = function() {
  // start the web server
  return app.listen(function() {
    app.emit('started');
    var baseUrl = app.get('url').replace(/\/$/, '');
    console.log('Web server listening at: %s', baseUrl);
    if (app.get('loopback-component-explorer')) {
      var explorerPath = app.get('loopback-component-explorer').mountPath;
      console.log('Browse your REST API at %s%s', baseUrl, explorerPath);
    }
  });
};

// start of first change
app.use(loopback.cookieParser('secret'));
// end of first change

// Bootstrap the application, configure models, datasources and middleware.
// Sub-apps like REST API are mounted via boot scripts.
boot(app, __dirname, function(err) {
  if (err) throw err;

  // start of second change
  app.remotes().after('Person.login', function (ctx, next) {
    if (ctx.result.id) {
      var opts = {signed: true};
      if (ctx.req.body.rememberme !== false) {
        opts.maxAge = 1209600000;
      }
      ctx.res.cookie('authorization', ctx.result.id, opts);
    }
    next();
  });
  app.remotes().after('Person.logout', function (ctx, next) {
    ctx.res.cookie('authorization', '');
    next();
  });
  // end of second change

  // start the server if `$ node server.js`
  if (require.main === module)
    app.start();
});

The first change configures the cookie parser to use ‘secret’ as the cookie signing secret, thereby enabling signed cookies. You need to do this because although LoopBack looks for an access token in either of the cookies ‘authorization’ or ‘access_token’, it requires that such a cookie be signed. Actually, this requirement is pointless. Signing a cookie is intended to ensure that the cookie hasn’t been modified. But there’s no danger of you modifying the access token. After all, you could have sent the access token in unsigned form, as an ordinary parameter. Thus, you don’t need to worry about the cookie signing secret being hard to guess, unless you’re using signed cookies for something else.

The second change sets up some postprocessing for the Person.login and Person.logout methods. For Person.login, you want to take the resulting access token and send it to the client as the signed cookie ‘authorization’ also. The client may add one more property to the credentials parameter, rememberme, indicating whether to make the cookie persistent for 2 weeks. The default is true. The login method itself will ignore this property, but the postprocessor will check it.

For Person.logout, you want to clear out this cookie.

You can see the results of these changes right away in the StrongLoop API Explorer. Normally after a Person.login request, you would have to copy the access token, paste it into the form at the top right, and click Set Access Token. But with these changes, you don’t have to do any of that. The access token is automatically saved as the cookie ‘authorization’, and sent back on each subsequent request. When the Explorer is displaying the response headers from Person.login, it omits the cookie, because JavaScript is never allowed to see Set-Cookie headers. But rest assured, the cookie is there.

On the client side, on a page reload you would see if the cookie ‘authorization’ exists. If so, you need to update your record of the current userId. Probably the easiest way to do this is to store the userId in a separate cookie on successful login, so you can retrieve it on a page reload.

The Fragment Identifier

As I’m visiting a web site that has been implemented as an SPA, the URL in my browser’s address bar might look something like “https://example.com/#/my-photos/37”. The fragment identifier portion of this, “#/my-photos/37”, is already a collection of state information that could be viewed as session data. In this case, I’m probably viewing one of my photos, the one whose ID is 37.

You may decide to embed other session data within the fragment identifier. Recall that in the previous section, with the access token stored in the cookie ‘authorization’, you still needed to keep track of the userId somehow. One option is to store it in a separate cookie. But another approach is to embed it in the fragment identifier. You could decide that while I’m logged in, all the pages I visit will have a fragment identifier beginning with “#/u/XXX”, where XXX is the userId. So in the previous example, the fragment identifier might be “#/u/59/my-photos/37” if my userId is 59.

Theoretically, you could embed the access token itself in the fragment identifier, avoiding any need for cookies or web storage. But that would be a bad idea. My access token would then be visible in the address bar. Anyone looking over my shoulder with a camera could take a snapshot of the screen, thereby gaining access to my account.

One final note: it is possible to set up an SPA so that it doesn’t use fragment identifiers at all. Instead it uses ordinary URLs like “http://example.com/app/dashboard” and “http://example.com/app/my-photos/37”, with the server configured to return the top level HTML for your SPA in response to a request for any of these URLs. Your SPA then does its routing based on the path (e.g. “/app/dashboard” or “/app/my-photos/37”) instead of the fragment identifier. It intercepts clicks on navigation links, and uses History.pushState() to push the new URL, then proceeds with routing as usual. It also listens for popstate events to detect the user clicking the back button, and again proceeds with routing on the restored URL. The full details of how to implement this are beyond the scope of this article. But if you use this technique, then obviously you can store session data in the path instead of the fragment identifier.

Web Storage

Web storage is a mechanism for JavaScript to store data within the browser. Like cookies, web storage is separate for each origin. Each stored item has a name and a value, both of which are strings. But web storage is completely invisible to the server, and it offers much greater storage capacity than cookies. There are two types of web storage: local storage and session storage.

An item of local storage is visible across all tabs of all windows, and persists even after the browser is closed. In this respect, it behaves somewhat like a cookie with an expiration date very far in the future. Thus, it is suitable for storing an access token in the case where the user has checked “keep me logged in” on the login form.

An item of session storage is only visible within the tab where it was created, and it disappears when that tab is closed. This makes its lifetime very different from that of any cookie. Recall that a session cookie is still visible across all tabs of all windows.

If you use the AngularJS SDK for LoopBack, the client side will automatically use web storage to save both the access token and the userId. This happens in the LoopBackAuth service in js/services/lb-services.js. It will use local storage, unless the rememberMe parameter is false (normally meaning the “keep me logged in” checkbox was unchecked), in which case it will use session storage.

The result is that if I log in with “keep me logged in” unchecked, and I then open a link in a new tab or window, I won’t be logged in there. Most likely I’ll see the login screen. You can decide for yourself whether this is acceptable behavior. Some might consider it a nice feature, where you can have several tabs, each logged in as a different user. Or you might decide that hardly anyone uses shared computers any more, so you can just omit the “keep me logged in” checkbox altogether.

So how would the session data handling look if you decide to go with the AngularJS SDK for LoopBack? Suppose you have the same situation as before on the server side: you’ve defined a Person model, extending the User model, and you’ve exposed the Person model over REST. You won’t be using cookies, so you won’t need any of the changes described earlier.

On the client side, somewhere in your outermost controller, you probably have a variable like $scope.currentUserId which holds the userId of the currently logged in user, or null if the user is not logged in. Then to handle page reloads properly, you just include this statement in the constructor function for that controller:

$scope.currentUserId = Person.getCurrentId();

It’s that easy. Add ‘Person’ as a dependency of your controller, if it isn’t already.

IndexedDB

IndexedDB is a newer facility for storing large amounts of data in the browser. You can use it to store data of any JavaScript type, such as an object or array, without having to serialize it. All requests against the database are asynchronous, so you get a callback when the request is completed.

You might use IndexedDB to store structured data that’s unrelated to any data on the server. An example might be a calendar, a to-do list, or saved games that are played locally. In this case, the application is really a local one, and your web site is just the vehicle for delivering it.

At present, Internet Explorer and Safari only have partial support for IndexedDB. Other major browsers support it fully. One serious limitation at the moment, though, is that Firefox disables IndexedDB entirely in private browsing mode.

As a concrete example of using IndexedDB, let’s take the sliding puzzle application by Pavol Daniš, and tweak it to save the state of the first puzzle, the Basic 3×3 sliding puzzle based on the AngularJS logo, after each move. Reloading the page will then restore the state of this first puzzle.

I’ve set up a fork of the repository with these changes, all of which are in app/js/puzzle/slidingPuzzle.js. As you can see, even a rudimentary usage of IndexedDB is quite involved. I’ll just show the highlights below. First, the function restore gets called during page load, to open the IndexedDB database:

/*
 * Tries to restore game
 */
this.restore = function(scope, storekey) {
    this.storekey = storekey;
    if (this.db) {
        this.restore2(scope);
    }
    else if (!window.indexedDB) {
        console.log('SlidingPuzzle: browser does not support indexedDB');
        this.shuffle();
    }
    else {
        var self = this;
        var request = window.indexedDB.open('SlidingPuzzleDatabase');
        request.onerror = function(event) {
            console.log('SlidingPuzzle: error opening database, ' + request.error.name);
            scope.$apply(function() { self.shuffle(); });
        };
        request.onupgradeneeded = function(event) {
            event.target.result.createObjectStore('SlidingPuzzleStore');
        };
        request.onsuccess = function(event) {
            self.db = event.target.result;
            self.restore2(scope);
        };
    }
};

The request.onupgradeneeded event handles the case where the database doesn’t exist yet. In this case, we create the object store.

Once the database is open, the function restore2 is called, which looks for a record with a given key (which will actually be the constant ‘Basic’ in this case):

/*
 * Tries to restore game, once database has been opened
 */
this.restore2 = function(scope) {
    var transaction = this.db.transaction('SlidingPuzzleStore');
    var objectStore = transaction.objectStore('SlidingPuzzleStore');
    var self = this;
    var request = objectStore.get(this.storekey);
    request.onerror = function(event) {
        console.log('SlidingPuzzle: error reading from database, ' + request.error.name);
        scope.$apply(function() { self.shuffle(); });
    };
    request.onsuccess = function(event) {
        if (!request.result) {
            console.log('SlidingPuzzle: no saved game for ' + self.storekey);
            scope.$apply(function() { self.shuffle(); });
        }
        else {
            scope.$apply(function() { self.grid = request.result; });
        }
    };
}

If such a record exists, its value replaces the grid array of the puzzle. If there is any error in restoring the game, we just shuffle the tiles as before. Note that grid is a 3×3 array of tile objects, each of which is fairly complex. The great advantage of IndexedDB is that you can store and retrieve such values without having to serialize them.

We use $apply to inform AngularJS that the model has been changed, so the view will be updated appropriately. This is because the update is happening inside a DOM event handler, so AngularJS wouldn’t otherwise be able to detect the change. Any AngularJS application using IndexedDB will probably need to use $apply for this reason.

After any action that would change the grid array, such as a move by the user, the function save is called which adds or updates the record with the appropriate key, based on the updated grid value:

/*
 * Tries to save game
 */
this.save = function() {
    if (!this.db) {
        return;
    }
    var transaction = this.db.transaction('SlidingPuzzleStore', 'readwrite');
    var objectStore = transaction.objectStore('SlidingPuzzleStore');
    var request = objectStore.put(this.grid, this.storekey);
    request.onerror = function(event) {
        console.log('SlidingPuzzle: error writing to database, ' + request.error.name);
    };
    request.onsuccess = function(event) {
        // successful, no further action needed
    };
}

The remaining changes are to call the above functions at appropriate times. You can review the commitshowing all of the changes. Note that we are calling restore only for the basic puzzle, not for the three advanced puzzles. We exploit the fact that the three advanced puzzles have an api attribute, so for those we just do the normal shuffling.

What if we wanted to save and restore the advanced puzzles also? That would require some restructuring. In each of the advanced puzzles, the user can adjust the image source file and the puzzle dimensions. So we’d have to enhance the value stored in IndexedDB to include this information. More importantly, we’d need a way to update them from a restore. That’s a bit much for this already lengthy example.

Conclusion

In most cases, web storage is your best bet for storing session data. It’s fully supported by all major browsers, and it offers much greater storage capacity than cookies.

You would use cookies if your server is already set up to use them, or if you need the data to be accessible across all tabs of all windows, but you also want to ensure it will be deleted when the browser is closed.

You already use the fragment identifier to store session data that’s specific to that page, such as the ID of the photo the user is looking at. While you could embed other session data in the fragment identifier, this doesn’t really offer any advantage over web storage or cookies.

Using IndexedDB is likely to require a lot more coding than any of the other techniques. But if the values you’re storing are complex JavaScript objects that would be difficult to serialize, or if you need a transactional model, then it may be worthwhile. Source: Toptal.

The Art of War Applied To Software Development

The following article is a guest post from Toptal. Toptal is an elite network of freelancers that enables businesses to connect with the top 3% of software engineers and designers in the world.

If you work in the software industry, it’s likely that you have heard about the divide and conquer design paradigm, which basically consists of recursively splitting a problem into two or more sub-problems (divide), until these become simple enough to be solved directly (conquer).

What you might not know is that this paradigm originates from an old political strategy (the name is derived from the Latin saying divide et impera) that suggests it is possible to maintain control over one’s subordinates or subjects by encouraging dissent between them.

This strategy has been used by countless politicians and military leaders throughout history, such as Julius Caesar (who used it during the Gallic Wars to defeat the militarily strong Gauls) and Napoleon (the French artillery expert would divide the enemy troops so no portion was stronger than his own troops, and then disrupt their communications, impeding enemy efforts to coordinate and execute attacks).

The Art Of War: Ancient Principles Applied To Development

However, the divide and conquer rule is not the only political strategy that can be applied to software development. Although politics and warfare have little to do with software development, just like politicians and generals, developers must lead subordinates, coordinate efforts between teams, find the best strategies to resolve problems, and administer resources.

Sun Tzu’s principles and teachings have practical applications in politics, business, sports, and software development.

Sun Tzu’s principles and teachings have practical applications in politics, business, sports, and software development.

The Art of War is an ancient military treatise written in the fifth century B.C. and attributed to Sun Tzu, an ancient Chinese military strategist, whose theories had a profound influence on both Eastern and Western philosophy.

Despite its age, the text is still included in the syllabus at many military schools in East Asia and it’s listed as a recommended reading in some military academies in the West. The text is divided into 13 chapters, each one devoted to a different aspect of warfare.

However, in addition to warfare, Sun Tzu’s principles and teachings have practical applications in politics, business, sports, and, believe it or not, software development. In fact, you might just be applying some of these principles in your daily routine, without even knowing their origins.

Detailed below, you will a find a brief list of basic tactics and tips explained in the Art of War. They can probably be applied to your job in the software industry, or any of a number of other industries.

Time Is Crucial In Any Campaign

Chapter II, paragraph 2

“When you engage in actual fighting, if victory is long in coming, then men’s weapons will grow dull and their ardor will be damped.”

This principle can be applied to software development, as a rule describing the relationship between the length of development cycles and the developer’s morale.

If a group of developers work on the same projects for months, with no clear goals or end in sight, they may become frustrated and their productivity may decline.

Divide your development roadmap into easily achievable goals and milestones. It’s good for morale.

Divide your development roadmap into easily achievable goals and milestones. It’s good for morale.

Software development is an intellectual endeavour, so motivation is the main fuel for productivity. Working every day without perceiving that your work is generating real results can be very demotivating.

As indicated in some agile methodologies, the development roadmap should be divided into several goals and milestones, which the team might be able to achieve in short timeframes, and they are going to give them a sense of progress and achievement.

Chapter II, paragraph 18

“In war, then, let your great object be victory, not lengthy campaigns.”

This phrase can be interpreted in two ways:

First, it can be seen as a precursor of the UNIX philosophy: Write programs that do one thing and do it well. When developing software, you must always keep in mind the main objective of the program, the key feature that it provides, or the biggest problem that it solves, and ensure proper implementation.

Sometimes you might get inspired and think of a really cool feature to add, but do not forget that applications that have lot of infrequently used features have a disparaging name: bloatware.

Second, the statement may also be considered as a precursor for one of the lean software development principles: Deliver as fast as possible.

The sooner you deliver software without major defects, the sooner you will get feedback from the client, and you will be able to incorporate the changes into the next iteration.

If on the other hand, you deliver non-working software, you will miss out on valuable feedback, because clients won’t get a chance to test it properly. This will make the next stage of development more difficult, or impossible in situations where your next iteration depends on customer feedback.

No Leadership, No Results

Chapter III, paragraph 11

“Now the general is the bulwark of the State; if the bulwark is complete at all points, the State will be strong; if the bulwark is defective, the State will be weak.”

This quote describes the importance of the role of the manager in a development team: the success of a project depends on the strength of all people involved, and the manager is the bulwark of the project. Responsibility starts at the top.

Responsibility starts at the top. If your team lead is bad, no amount of talented engineers will help.

Responsibility starts at the top. If your team lead is bad, no amount of talented engineers will help.

Even though developers frequently work alone (each sitting behind a computer, with limited communication with coworkers), that does not mean that they don’t need good leadership. Project managers are in charge of keeping the team on track, ensuring effective communication and dispute resolution, and leaders, obviously, define the priorities of the project (among other tasks), so their role should not be underestimated. Neither should their responsibility if something goes wrong. Imagine what would happen to a military leader whose unit failed to perform its duty in the field of battle?

A team can produce great software even if it has a few bad apples in development positions, but that’s unlikely to happen if the project manager is the bad apple, no matter how many rockstar developers the team has.

Chapter VI, paragraph 28

“Do not repeat the tactics which have gained you one victory, but let your methods be regulated by the infinite variety of circumstances.”

Sometimes, when starting a project, it’s tempting to use the same set of technologies we used in previously successful projects (the same programming language, the same libraries, the same server, etc). However, unless the requirements of the new projects are exactly the same as previous ones, this might be the wrong approach.

In programming, as in most domains, the panacea (a supposed remedy capable of curing all diseases) does not exist. There is no single combination of technologies that you can use for solving all problems; each technology has its upsides and downsides.

Of course, learning a new programming language or using an unknown API might initially be expensive but in the long term, the quality of the software will be superior and you will become a better developer.

Chapter XIII, paragraph 27

“Hence it is only the enlightened ruler and the wise general who will use the highest intelligence of the army for purposes of spying, and thereby they achieve great results. Spies are a most important element in war, because on them depends an army’s ability to move.”

This phrase may be interpreted as the importance of using monitoring tools and logging libraries during the maintenance phase.

Although sometimes clients might not think so, development does not end when you get a stable and fully tested release. Software is always evolving, either by fixing bugs, adding new features or improving efficiency.

And there is no better source of information for knowing what changes to make than having spies monitoring the software in production environments, checking which features are used the most, the most common errors and the lengthiest operations.

Error reports, logging entries and usage data are fundamental for detecting bugs, identifying bottlenecks and other issues since it is not always possible to reproduce the same conditions in controlled testing environments.

Teamwork And Motivation

Chapter X, paragraph 24

“He who advances without seeking fame, Who retreats without escaping blame, He whose one aim is to protect his people and serve his lord, The man is a jewel of the Realm.”

Basically, this is the ancient Chinese version of “there’s no I in team”. It is more important to work together with others rather than to pursue personal gain.

Software development is a complex activity that requires developers to work effectively as a team. A good developer is not the one who fixes the most bugs, implements the most features or finishes assignments ahead of schedule; a good developer is the one who helps the team reach its goals.

Teamwork wins battles. Remember, the best developers are inspiring individuals who help other team members reach their objectives.

Teamwork wins battles. Remember, the best developers are inspiring individuals who help other team members reach their objectives.

Claiming credit for everything you’ve done, not recognizing your errors or blaming others for them, or calling yourself a code ninja might fool some inexperienced managers and might even get you a raise, but you will become a counterproductive member of your team.

Chapter VII, paragraph 21

“Ponder and deliberate before you make a move.”

This phrase indicates the importance of team development meetings, such as those proposed by agile methodologies.

When working on a team, it is important to discuss any major changes before implementing them. It doesn’t matter if you are the team leader, or if you are the person with the most experience of the subject, you should always talk with, or at least inform, the rest of the team.

Remember that other developers could give you insights into unfamiliar parts the software. This means they could start implementing the changes faster than expected, because they could be fully aware of the effects of said changes.

Chapter X, paragraph 25

“Regard your soldiers as your children, and they will follow you into the deepest valleys; look upon them as your own beloved sons, and they will stand by you even unto death.”

This quote indicates the importance of motivation, a principle of management that is sometimes forgotten by managers and team leaders. Motivated developers will write better code, work faster, commit less errors and be more willing to put in extra hours.

Motivation must be generated by managers, by taking genuine interest in their subordinates, listening to them, caring about their work-life balance, building positive work environments and caring about their career paths.

Also, you should not mistake motivation with remuneration. Recent studies demonstrates that money do not motivate most workers, money is mostly good at attracting and retaining employees, but not at make them happy about their jobs. So raises and promotions should not be seen as motivational tools.

Thinking Outside The Box

Chapter V, paragraph 7, 8 and 9

“There are not more than five musical notes, yet the combinations of these five give rise to more melodies than can ever be heard.”

“There are not more than five primary colors, yet in combination they produce more hues than can ever been seen.”

“There are not more than five cardinal tastes, yet combinations of them yield more flavors than can ever be tasted.”

One of the good things about programming is that the possibilities are endless; you can develop basically wherever you want (at least, as long is not an NP-complete problem).

Mobile apps, websites, games, desktop applications… if you know programming, all of them are within your reach.

If you’re a talented developer, you need to think outside the box. The box is there to prevent incompetent people from wrecking stuff. It’s not for you.

If you’re a talented developer, you need to think outside the box. The box is there to prevent incompetent people from wrecking stuff. It’s not for you.

Chapter III, paragraph 1

“In the practical art of war, the best thing of all is to take the enemy’s country whole and intact; to shatter and destroy it is not so good. So, too, it is better to capture an army entire than to destroy it, to capture a regiment, a detachment or a company entire than to destroy them.”

When working on a project with a large code base, it is common to find modules or sections of code that have been implemented with bad practices or by using deprecated libraries. Although it might be tempting to erase (or destroy) this code, it might not be the best idea for several reasons:

  • Legacy code is not necessarily bad, sometimes it is good code that was written when other methodologies and technologies were considered the way to go. However, just because it is old doesn’t mean that it is not working.
  • You might lose time fixing code that still works instead of focusing on fixing other, more critical parts of the code.
  • Unless you are really sure of what you are doing, replacing a section of code that works means you are risking introducing new errors or bugs.

This does not mean that the phrase “If it ain’t broke, don’t fix it” is a good strategy, but that every project has priorities, goals and time constraints. So, if you find code that could be improved, discuss it with the rest of the team or with the project manager in order to figure out when to optimize it.

Chapter VIII, paragraph 3

“There are roads which must not be followed, armies which must not be attacked, towns which must not be besieged, positions which must not be contested, commands of the sovereign which must not be obeyed.”

Even it does not say it directly, we could interpret this principle as a warning to avoid anti-patterns.

Although using an anti-pattern may resolve a short-term issue, you should remember that in the long-term it is going to be counter-productive. So, no matter how much time you save, how many bugs you fix or how convenient it is for you, avoid them.

Still, there are times you may be tempted to use an anti-pattern to resolve an urgent task, promising yourself you will implement a proper fix when you have more time, but remember one of Murphy’s laws: All quick fixes become permanent changes.

Conclusion

Although developing software is different from commanding soldiers in war or leading a country, all that they must solve problems that require teamwork, good leadership, efficiency and long-term solutions.

However, the Art of War is not the only book which contains principles that may be applied to software development. Niccolò Machiavelli’s The Prince, is an example.

In fact, here is a list of quotes from Machiavelli that are still relevant. Try guessing which are the corresponding principles in the world of software development.

  1. The lion cannot protect himself from traps, and the fox cannot defend himself from wolves. One must therefore be a fox to recognize traps, and a lion to frighten wolves.
  2. Never attempt to win by force what can be won by deception.
  3. Never was anything great achieved without danger.
  4. Whosoever desires constant success must change his conduct with the times.
  5. Men in general judge more from appearances than from reality. All men have eyes, but few have the gift of penetration.
  6. He who wishes to be obeyed must know how to command.
  7. Wisdom consists of knowing how to distinguish the nature of trouble, and in choosing the lesser evil.
  8. There is no avoiding war; it can only be postponed to the advantage of your enemy.
  9. Nature creates few men brave; industry and training makes many.

Fixing the “Heartbleed” OpenSSL Bug: A Tutorial for Sys Admins

The following article is a guest post from Toptal. Toptal is an elite network of freelancers that enables businesses to connect with the top 3% of software engineers and designers in the world.

So what exactly is the bug anyway?

Here’s a very quick rundown:

A potentially critical problem has surfaced in the widely used OpenSSL cryptographic library. It is nicknamed “Heartbleed” because the vulnerability exists in the “heartbeat extension” (RFC6520) to the Transport Layer Security (TLS)  and it is a memory leak (“bleed”) issue.  User passwords and other important data may have been compromised on any site affected by the vulnerability.

The vulnerability is particularly dangerous for two reasons:

  1. Potentially critical data is leaked.
  2. The attack leaves no trace.

The affected OpenSSL versions are 1.0.1 through 1.0.1f, 1.0.2-beta, and 1.0.2-beta1.

Who is affected by the problem?

Short answer:  Anyone and everyone who uses these versions of OpenSSL.

And that’s a LOT of companies and a LOT of people.

Before we get into our Heartbleed tutorial, here’s just a brief sampling of major companies and websites that are known to have been affected and that needed to patch their sites:  GmailYahoo MailIntuit TurboTaxUSAA, Dropbox, Flickr, Instagram, PinterestSoundCloud, Tumblr, GitHubGoDaddyBoingo Wireless, and many more.

If you're wondering how to protect against openssl Heartbleed, start by using the Heartbleed test.

Many, many corporate websites, of companies of all sizes, have been (or still need to be!) patched to fix the Heartbleed vulnerability.

The vulnerability has existed since December 31, 2011, with OpenSSL being used by about 66% of Internet hosts.

As a user, chances are that sites you frequent regularly are affected and that your data may have been compromised. As a developer or sys admin, sites or servers you’re responsible for are likely to have been affected as well.

So what do I need to do to protect myself if I use any of the affected sites?

The main thing you should do immediately is to change your passwords for any of the affected sites for which you have a login account.

And what do I need to do to fix and protect against Heartbleed if I’m the sys admin for a site that uses OpenSSL?

If you’re using OpenSSL 1.0.1, do one of the following immediately:

  • Upgrade to OpenSSL 1.0.1g, or
  • Recompile OpenSSL with -DOPENSSL_NO_HEARTBEATS.

If you’re using OpenSSL 1.0.2, the vulnerability will be fixed in 1.0.2-beta2 but you can’t wait for that.  In the interim, do one of the following immediately:

  • Revert to OpenSSL 1.0.1g, or
  • Recompile OpenSSL with -DOPENSSL_NO_HEARTBEATS.

Most distributions (e.g., Ubuntu, Fedora, Debian, Arch Linux) have upgraded their packages already.  In cases like Gentoo, you can upgrade to a patched ebuild.

Once you’ve upgraded (or recompiled) and have established a secure version on your server:

  • Be sure to restart all potentially affected processes.  Major daemons affected by the bug include Apache, Nginx, OpenVPN, and sshd; basically anything and everything linked against libssl. (Note that a restart of these daemons should be sufficient.  There should be no need to rebuild these binaries since they are dynamically linked with the openssl libraries.)
  • Verify that you are no longer vulnerable using tools like this online test or this tool on GitHub or this tool on Pastebin.

If your infrastructure was vulnerable, there are Heartbleed tutorial steps that you can and should take.  A useful list of such mitigations is available here.

More gory Heartbleed details, for those who are interested…

As explained in the GitHub commit for the fix, a missing bounds check in the handling of the TLS heartbeat extension could be exploited to reveal up to 64k of memory to a connected client or server.

While the exposed memory could potentially just be garbage, it could just as easily turn out to be extremely valuable to a malicious attacker.

Here’s how the Heartbleed vulnerability works:  An attacker provides the payload as well as the payload length.  However, no validation is done to confirm that the payload length was actually provided by the attacker.  If the payload length was not provided, an out-of-bounds read occurs, which in turn leaks process memory from the heap.

Leaking previous request headers can be a very serious security problem. Specifically, a prior user’s login post data might still be available with their username, password, and cookies, all of which can then be exposed and exploited. Moreover, although private key leakage through Heartbleed was initially deemed to be unlikely, it has been verified that private SSL keys can be stolen by exploiting this vulnerability.

Fixing Heartbleed is critical as it has been confirmed that private SSL keys can be stolen this way.

The vulnerability is also made possible due to OpenSSL’s silly use of a malloc() cache.  By wrapping away libc functions and not actually freeing memory, the exploitation countermeasures in libc are never given the chance to kick in and render the bug useless.

Additional details on these ways to fix Heartbleed are available here and here.

And, for what it’s worth, here’s a more amusing perspective.

Kudos to the discoverer, Neel Mehta of Google Security, as well as Adam Langley and Bodo Moeller who promptly provided the patch and helped sys admins determine how to fix Heartbleed. I also encourage you to educate yourself on some of the other common web security vulnerabilities to avoid issues in the future.

Avoid the 10 Most Common Mistakes Web Developers Make: A Tutorial for Developers

The following article is a guest post from Toptal. Toptal is an elite network of freelancers that enables businesses to connect with the top 3% of software engineers and designers in the world.

Since the term the World Wide Web was coined back in 1990, web application development has evolved from serving static HTML pages to completely dynamic, complex business applications.

Today we have thousands of digital and printed resources that provide step-by-step instructions about developing all kinds of different web applications. Development environments are “smart” enough to catch and fix many mistakes that early developers battled with regularly. There are even many different development platforms that easily turn simple static HTML pages into highly interactive applications.

All of these development patterns, practices, and platforms share common ground, and they are all prone to similar web development issues caused by the very nature of web applications.

The purpose of these web development tips is to shed light on some of the common mistakes made in different stages of the web development process and to help you become a better developer. I have touched on a few general topics that are common to virtually all web developers such as validation, security, scalability, and SEO. You should of course not be bound by the specific examples I’ve described in this guide, as they are listed only to give you an idea of the potential problems you might encounter.

Think of all the web development mistakes that could be avoided at this campout!

Common mistake #1: Incomplete input validation

Validating user input on client and server side is simply a must do! We are all aware of the sage advice “do not trust user input” but, nevertheless, mistakes stemming from validation happen all too often.

One of the most common consequences of this mistake is SQL Injection which is in OWASP Top 10 year after year.

Remember that most front-end development frameworks provide out-of-the-box validation rules that are incredibly simple to use. Additionally, most major back-end development platforms use simple annotations to assure that submitted data are adhering to expected rules. Implementing validation might be time consuming, but it should be part of your standard coding practice and never set aside.

Common mistake #2: Authentication without proper Authorization

Before we proceed, let’s make sure we are aligned on these two terms. As stated in the 10 Most Common Web Security Vulnerabilities:

Authentication: Verifying that a person is (or at least appears to be) a specific user, since he/she has correctly provided their security credentials (password, answers to security questions, fingerprint scan, etc.).

Authorization: Confirming that a particular user has access to a specific resource or is granted permission to perform a particular action.

Stated another way, authentication is knowing who an entity is, while authorization is knowing what a given entity can do.

Let me demonstrate this issue with an example:

Consider that your browser holds currently logged user information in an object similar to the following:

{
    username:'elvis',
    role:'singer',
    token:'123456789'
}

When doing a password change, your application makes the POST:

POST /changepassword/:username/:newpassword

In your /changepassword method, you verify that user is logged and  token has not expired. Then you find the user profile based on the :username parameter, and you change your user’s password.

So, you validated that your user is properly logged-in, and then you executed his request thus changing his password. Process seems OK, right? Unfortunately, the answer is NO!

At this point it is important to verify that the user executing the action and the user whose password is changed are the same. Any information stored on the browser can be tampered with, and any advanced user could easily update username:'elvis' to username:'Administrator' without using anything else but built-in browser tools.

So in this case, we just took care of Authentication making sure that the user provided security credentials. We can even add validation that /changepassword method can only be executed by Authenticated users. However, this is still not enough to protect your users from malicious attempts.

You need to make sure that you verify actual requestor and content of request within your /changepasswordmethod and implement proper Authorization of the request making sure that user can change only her data.

Authentication and Authorization are two sides of the same coin. Never treat them separately.

Common mistake #3: Not ready to scale

In today’s world of high speed development, startup accelerators, and instant global reach of great ideas, having your MVP (Minimum Viable Product) out in the market as soon as possible is a common goal for many companies.

However, this constant time pressure is causing even good web development teams to often overlook certain issues. Scaling is often one of those things teams take for granted. The MVP concept is great, but push it too far, and you’ll have serious problems. Unfortunately, selecting a scalable database and web server and separating all application layers on independent scalable servers is not enough. There are many details you need to think about if you wish to avoid rewriting significant parts of your application later – which becomes a major web development problem.

For example, say that you choose to store uploaded profile pictures of your users directly on a web server. This is a perfectly valid solution–files are quickly accessible to the application, file handling methods are available in every development platform, and you can even serve these images as static content, which means minimum load on your application.

But what happens when your application grows, and you need to use two or more web servers behind a load balancer? Even though you nicely scaled your database storage, session state servers, and web servers, your application scalability fails because of a simple thing like profile images. Thus, you need to implement some kind of file synchronization service (that will have a delay and will cause temporary 404 errors) or another workaround to assure that files are spread across your web servers.

This bloated blowfish is full of web development tips and tutorials to avoid common mistakes.

What you needed to do to avoid the problem in the first place was just use shared file storage location, database, or any other remote storage solution. It would have probably cost few extra hours of work to have it all implemented, but it would have been worth the trouble.

Common mistake #4: Wrong or missing SEO

The root cause of incorrect or missing SEO best practices on web sites is misinformed “SEO specialists”. Many web developers believe that they know enough about SEO and that it is not especially complex, but that’s just not true. SEO mastery requires significant time spent researching best practices and the ever-changing rules about how Google, Bing, and Yahoo index the web. Unless you constantly experiment and have accurate tracking + analysis, you are not a SEO specialist, and you should not claim to be one.

Furthermore, SEO is too often postponed as some activity that is done at the end. This comes at a high price of web development issues. SEO is not just related to setting good content, tags, keywords, meta-data, image alt tags, site map, etc. It also includes eliminating duplicate content, having crawlable site architecture, efficient load times, intelligent back linking, etc.

Like with scalability, you should think about SEO from the moment you start building your web application, or you might find that completing your SEO implementation project means rewriting your whole system.

Common mistake #5: Time or processor consuming actions in request handlers

One of the best examples of this mistake is sending email based on a user action. Too often developers think that making a SMTP call and sending a message directly from user request handler is the solution.

Let’s say you created an online book store, and you expect to start with a few hundred orders daily. As part of your order intake process, you send confirmation emails each time a user posts an order. This will work without problem at first, but what happens when you scale your system, and you suddenly get thousands of requests sending confirmation emails? You either get SMTP connection timeouts, quota exceeded, or your application response time degrades significantly as it is now handling emails instead of users.

Any time or processor consuming action should be handled by an external process while you release your HTTP requests as soon as possible. In this case, you should have an external mailing service that is picking up orders and sending notifications.

Common mistake #6: Not optimizing bandwidth usage

Most development and testing takes place in a local network environment. So when you are downloading 5 background images each being 3MB or more, you might not identify an issue with 1Gbit connection speed in your development environment. But when your users start loading a 15MB home page over 3G connections on their smartphones, you should prepare yourself for a list of complaintsand problems.

Optimizing your bandwidth usage could give you a great performance boost, and to gain this boost you probably only need a couple of tricks. There are few things that many good web deveopers do by default, including:

  1. Minification of all JavaScript
  2. Minification of all CSS
  3. Server side HTTP compression
  4. Optimization of image size and resolution

Common mistake #7: Not developing for different screen sizes

Responsive design has been a big topic in the past few years. Expansion of smartphones with different screen resolutions has brought many new ways of accessing online content, which also comes with a host of web development issues. The number of website visits that come from smartphones and tablets grows every day, and this trend is accelerating.

In order to ensure seamless navigation and access to website content, you must enable users to access it from all types of devices.

There are numerous patterns and practices for building responsive web applications. Each development platform has its own tips and tricks, but there are some frameworks that are platform independent. The most popular is probably Twitter Bootstrap. It is an open-source and free HTML, CSS, and JavaScript framework that has been adopted by every major development platform. Just adhere to Bootstrap patterns and practices when building your application, and you will get responsive web application with no trouble at all.

Common mistake #8: Cross browser incompatibility

The development process is, in most cases, under a heavy time pressure. Every application needs to be released as soon as possible and even good web developers are often focused on delivering functionality over design. Regardless of the fact that most developers have Chrome, Firefox, IE installed, they are using only one of these 90% of the time. It is common practice to use one browser during development and just as the application nears completion will you start testing it in other browsers. This is perfectly reasonable–assuming you have a lot of time to test and fix issues that show up at this stage.

However, there are some web development tips that can save you significant time when your application reaches the cross-browser testing phase:

  1. You don’t need to test in all browsers during development; it is time consuming and ineffective. However, that does not mean that you cannot switch browsers frequently. Use a different browser every couple of days, and you will at least recognize major problems early in development phase.
  2. Be careful of using statistics to justify not supporting a browser. There are many organizations that are slow in adopting new software or upgrading. Thousands of users working there might still need access to your application, and they cannot install the latest free browser due to internal security and business policies.
  3. Avoid browser specific code. In most cases there is an elegant solution that is cross-browser compatible.

Common mistake #9: Not planning for portability

Assumption is the mother of all problems! When it comes to portability, this saying is more true than ever. How many times have you seen issues in web development like hard coded file paths, database connection strings, or assumptions that a certain library will be available on the server? Assuming that the production environment will match your local development computer is simply wrong.

Ideal application setup should be maintenance-free:

  1. Make sure that your application can scale and run on a load-balanced multiple server environment.
  2. Allow simple and clear configuration–possibly in a single configuration file.
  3. Handle exceptions when web server configuration is not as expected.

Common mistake #10: RESTful anti patterns

RESTful API’s have taken their place in web development and are here to stay. Almost every web application has implemented some kind of REST services, whether for internal use or integrating with external system. But we still see broken RESTful patterns and services that do not adhere to expected practices.

Two of the most common mistakes made when writing a RESTful API are:

  1. Using wrong HTTP verbs. For example using GET for writing data. HTTP GET has been designed to be idempotent and safe, meaning that no matter how many times you call GET on the same resource, the response should always be the same and no change in application state should occur.
  2. Not sending correct HTTP status codes. The best example of this mistake is sending error messages with response code 200.
     HTTP 200 OK
     {
         message:'there was an error'
     }
    

You should only send HTTP 200 OK when the request has not generated an error. In the case of an error, you should send 400, 401, 500 or any other status code that is appropriate for the error that has occurred.

A detailed overview of standard HTTP status codes can be found here.

Wrap up

Web development is an extremely broad term that can legitimately encompass development of a website, web service, or complex web application.

The main takeaway of this web development guide is the reminder that you should always be careful about authentication and authorization, plan for scalability, and never hastily assume anything – or be ready to deal with a long list of web development problems!

 

Search This Blog
NetworkedBlogs