Fast forward one year and our saving account still looked pretty much the same. I was frustrated and didn’t know how we weren't achieving our targets. I had allowed enough budget for everything and it was impossible that we were spending more than my spreadsheet predicted. After a couple more months of failed savings attempts my strategy was to lower our savings targets because they clearly weren’t achievable.
Fortunately my wife stepped in. She recalculated our outgoings including what she thought we would need on a weekly basis. Every week she drew the cash for our weekly allowance and put in our wallets. This simple technique of having physical notes in our hands and getting rid of the bottomless card was revolutionary to our saving strategy. We were now aware of how much money we had to spend because it was a physical thing that wouldn't be there anymore if we spent it. With this new found awareness and control of our financial resources we were able to spend more carefully and ultimately able to meet – even exceed - our saving targets every month.
This parable, as you may have guessed, teaches a lesson on effective use of resources. If you don’t have a clear idea about how much resource you have, what you use it on you or how to use it sparingly, you will almost certainly squander your resources rendering your budget exhausted. And this applies to software development. By resource management in this context I mean how your code interacts with the resources the application platform has on offer such as memory, connections and processing power.
Bad resource management is rife in software development for two reasons. Firstly, resource management is abstracted away from today’s modern developers. Garbage collection and managed runtimes provide a safety net in which sloppy use of resources gets cleaned up or contained within a chaperoned runtime. Secondly, software developers are spoilt with exceptionally powerful hardware which doesn’t cost very much. Like Augustus Gloop – the greedy, overweight kid from Charlie and the Chocolate factory – developers can end up binging on rivers of CPU power, vats of RAM and giant pipes of bandwidth. And those that do will ultimately pay the price for such careless abundance.
To make sure this doesn't happen, here are six commandments of effective resource management in web application development.
1: Dispose your ResourcesUnnecessarily hanging onto resources – for example leaving connections open - is probably the single most common cause of failures in applications. As usage of a system increases so does access to any unmanaged resources it uses such has File Streams, Database Connections and Network connections (Http, TCP Connections). It is very easy write code which doesn't close connections and very hard to find the source of failure (like timeouts) when your site goes live and stops working.
To safeguard against evils like this being committed in code you have to identify them at develop time or runtime. During develop time, code reviews and having more eyes survey key bits of code is a great defence mechanism against mistakes such as these. During runtime, make sure you load test your application before it goes live as this will quickly expose any resource saturation such as connection pools filling up.
2: Keep your resources in syncThreading problems in code are even harder to identify than issues relating to bad connection management. Threading issues often exhibit random and unexpected behaviour, thereby making the resulting problems very hard to reproduce and solve.
If you are using any resources in a non thread safe way and you don’t apply the proper controls, resources in your application will end up in an invalid state due to read/write conflicts and your application will blow up unexpectedly.
There is no easy answer to dealing with concurrency and multi threaded applications but what is key is that you know what you are doing when working in this domain. If you don’t you will certainly end up in sticky situation where you have no idea why data does weird and spooky things on production.
Synchronization, Immutable Objects and Thread-Safe Wrappers are the used to design around potential concurrency issues. If you think you should be thinking about threading and not sure what to do, get help.
3: Use Resources as and when neededA crime I’ve seen too often is sacrificing resources for reusability or convenience.
Here is a common example:
I'm building an MVC Site and most pages require access to the logged in user profile details. Let’s create a base class for our view models and instantiate the user profile object in the base classes’ constructor and expose it as a public property. If the views don’t need all user data, no worries: better to save a bit of dev time and have a wee bit of resource spillage, right? It is kind of like the ‘angels share’ of whiskey which evaporates from barrels during fermentation process. It just happens and sounds poetic when you talk about it.
As the build progresses the Class we use to store the User Profile gets bigger and hydrating it becomes a more expensive task which involves calling out to a CRM and plugging it with loads of Facebook data. The person adding in the complexity doesn't check that this class is instantiated in for every single page view and lo and behold the site starts grinding to a halt
Resource management is actually very simple: use resources as and when needed and clean them up as soon as you have finished with them.
4: Use caching lastA colleague once pointed out that caching should be like a free lunch. You shouldn't rely on it but enjoy it when it’s there. Caching should be added once your application is stable, robust and performant.
Adding in caching too early and relying on it lends to inefficiencies at the root resource consumption layer. You don’t really need to worry about sprocs or indexes or Linq queries because we store everything in the cache, right? Wrong. Adding cache as a band aid on top of an inefficient layer isn’t scalable and creates pattern of bad behaviour across the whole solution. Your cache layer is transient and when it fails your flaky implementation below will collapse below your feet.
Adding in caching too early and relying on it also leads to instability. Cache by nature is transient and therefore can’t be 100% relied on. If you application expects durability of data then a cache based solution will let you down.
5: Beware State BucketsAnother perpetrator of resources crimes are buckets which allow developers to easily store and retrieve resources in the lifecycle of the application session or user session. Cache is one example and so is session state. Session state is often over used to deal with state related issues. As soon as things are bunged into session state it becomes another place for sloppy development to flourish. After a while your session starts to bloat and gets left lying around hogging up valuable resources on your servers.
If you are storing items in Cache or Session make sure it is absolutely necessary and there is no way around your state management conundrum. In most cases you will probably find an alternative to session state.
It is true to say that these commandments pertain to all software development and are pretty basic concepts that anyone will know. This should be the case but 9 times out of 10 when SITES GO BAD! It is due to a violation of one or more of these principles.
In the book Charlie and The Chocolate Factory Augustus Gloop ended up getting squeezed thin by being sucked into a pipe in a horrific sequence. He could have avoided this fate by not being a greedy, gluttonous arse. As a developer you should do the same.