0

I have an application that consists of multiple sections of which each section will need to load data from various API calls.

Now I'm thinking of taking advantage of Session variables(or caching) to store some data based on User ID so that in case of a user reloads the page continuously it would prevent unnecessary calls (except of course in certain cases where the data needs real time update).

This is my first time building a complex web application and I was wondering what would be a good practice to prevent the application from getting overloaded with unnecessary calls.

Thanks for any advice.

3
  • "each section will need to load data" -- does that mean you haven't written any code yet? If not, how could you know whether your application will be overloaded? Finish building the app then measure its performance. Think about caching and optimisation afterwards if (and only if) performance turns out to be a problem. Otherwise, YAGNI and Premature optimisation is the root of all evil Feb 5, 2020 at 8:41
  • Whats the target for your app? Do you need multiple servers? Then you need to think of how the caching should be done. Can you do the caching on the client? Can you make singel page app? I like to avoid all caching on the server. Data that can be cached will end up in the memory of the singel page app.
    – Mr Zach
    Feb 5, 2020 at 10:05
  • NOTE: session variables have a cost in both server memory, and in requiring any load balancers you have guarantee session affinity. I recommend a more shared-nothing approach and either have the client application cache things in JavaScript or just use standard caching. Feb 5, 2020 at 14:57

3 Answers 3

0

Your instinct about caching frequent calls is correct. While its very hard to predict future performance problems, you can plan ahead with a caching strategy now to make it easier to adjust your site on the fly later when you get some real traffic. There's two kinds of caching in ASP.NET that will give you some immediate benefits without being too hard to use: Session storage and Application Caching.

Session Storage essentially caches an object locally (kinda) on the user's computer for the duration of their session on your site. An object stuck into session for a given user is not generally available to the system unless its in the context of that user posting something to the server. So its a natural fit for stuff like the logged in user's details. You can store something like a User class for the current user in session, to avoid having to go look up their username/email/dob/etc from the database on each pageload, if for example you render that info on every screen. Session object are easy to create and retrieve as they are just listed by a key:

// Set up a session obj
Session["LoggedInUserDetail"] = new LoggedInUserDetail("Greg Smith", "gsmith", "admin");

// On future pageloads, fetch the object out of session
var loggedInUser = Session["LoggedInUserDetail"] as LoggedInUserDetail;
if (loggedInUser == null)
    // handle logged out user here
else 
    // render user details here.

Application Caching is like session, but instead of the object being stored on the client, they are stored on the server. One example of why you would use this instead of session would be for something like an expensive database call that every user will need but isn't tailored to each user. Like perhaps a large entity that's expensive to fetch from the database. You can write code such that the first user who requests this object waits for it to come from the database, but all future requests from either that user or different users will be able to get that object from memory instead of the database. Application Caching looks very similar to Session Storage, but you can tell the app how long to hold onto the object too, among other things. Here's a method that pulls a Widget object into cache and returns it on subsequent calls.

public Widget GetWidgetFromCache(int widgetParam)
{
    var keyName = "CachedWidget";
    var widgetFromCache = HttpContext.Current.Cache[keyName] as Widget;
    if (widgetFromCache != null)
        return widgetFromCache;

    // expensive call here
    var widgetFromDbase = SQLFactory.GetExpensiveWidget(widgetParam); 

    // put it into cache and return it.
    HttpContext.Current.Cache.Insert(keyName, widgetFromDbase, null, DateTime.Now.AddHours(1), Cache.NoSlidingExpiration);
    return widgetFromDbase;
}

With these two techniques, you can radically improve the performance of your app. You'll just have to understand that you can be working with slightly 'stale' data if its cached, and adjust your app accordingly. Having helper methods to help remove items from the cache when needed also helps. Give me a shout in the comments if you need help with that.

1
  • This is a good answer, but it is not complete without mentioning other types of caching. For example, the entire page could be cached either at the server or client.
    – John Wu
    Feb 8, 2020 at 1:37
1

"The perfect race car crosses the finish line in first place and immediately falls into pieces."
- Ferdinand Porsche

This quote isn't suggesting you should build things to break, but rather that you don't need to build things to not break beyond their purpose.
The perfect race car is "perfect" because exactly zero effort was wasted on its quality/performance after it has met its goals.

Don't overengineer!

This is my first time building a complex web application and I was wondering...

This is the classic overengineering situation. You've built the application in your mind and are already thinking on how to improve it and prevent common issues, before you've actually built the thing, seen if it works the way you intended it to, and if there are any issues.

It's a common thing to encounter, all developers encounter it (not just software developers, mind you), which is also why there are many guidelines here to remind you to not do it. From the top of my head:

Wikipedia's related entries on these linked pages lead you to many more philosophies on the topic, which all focus on the same core: don't spend effort on something you don't know you need.

Now I'm thinking of taking advantage of Session variables(or caching) to store some data based on User ID so that in case of a user reloads the page continuously it would prevent unnecessary calls

Before you start fixing this, you need to confirm two things:

  • There is a realistic expectation of this issue happening
  • This issue happening poses an actual problem, whose existence you need proof of (not just a hunch)

If you can't conclusively prove either of them, that's where it stops. This inherently means that if you don't have a working application, you cannot have tangible proof and therefore cannot already start optimizing this.

Does that mean you should develop your software thinking it won't have issues?

No, of course not.

But this is where clean coding comes into play. When you use clean coding principles, you're not fixing problems, but rather you are preparing the codebase for future changes, which will come about when you experience certain problems and need to make alterations to the codebase to solve them.

On your first pass, you don't fix existing problems. That's by definition impossible, as the code that supposedly causes the issues doesn't exist yet. On your first pass, you should only spend additional effort on paving the way for future fixes to be as effortless as reasonably possible.

(except of course in certain cases where the data needs real time update)

You're very close to a very important realization: things are not as simple as they look at first sight. You've already stumbled on an exception to the blanket solution you're trying to provide.

This same realization can be applied further: the application you have in your mind may not work in reality because things aren't as simple.
Your imaginary application doesn't have a compiler fact-checking its correctness. It's perfectly possible and highly likely that your mind has glossed over some implementation intricacies which may vastly change the landscape for your alleged problem (and its solution) to occur in.

And again, this is perfectly normal for developers to encounter. This isn't indicative of you being a bad developer. If anything, it shows a willingness to tackle the development process, and that's good.
But it does show that you haven't yet fallen down the "effort pit" (as an analogy to a money pit) that premature optimization leads you to.

0

Before you jump in to architectural decisions, take the time to design your interactions. I'm not talking about a big design up front. I'm talking to think through the interactions so that you understand the following before you commit to anything else:

  • Volatility of your data--how often does it change?
  • How stale can your data be?
  • If you fine tune your design, can you provide the same value with fewer interactions?
  • Is the data you need to assemble user specific?
  • What is your scaling plan?

Each of these impact how appropriate your architectural decisions are to the final product. For example, if the data is highly volatile and you need fresh data every time, caching isn't going to give you the benefit you desire. Also, if data is not user specific, global caching is more appropriate than session caching.

Planning to scale

Every successful application will need to scale. There are several factors to consider here, but with modern hardware the biggest limitations are going to be network and disk speeds. That means scaling out (adding additional servers) is going to give you much more capacity than scaling up (more memory and CPU).

When planning to scale out, Session storage is particularly problematic. The default implementation in ASP.Net (and Java Servlets, and ...) is to keep that information in memory associated with a session identifier. The session identifier is passed back to the server with each request--usually as a cookie. After the session expires the memory is reclaimed. With that implementation, your load balancer needs to maintain session affinity. That seriously limits scalability and adds complexity you don't need.

The best bet is to avoid Sessions altogether. Your options are to store user information in the browser, or ensure your cache keys also include the user id. There is a reason why the Single Page Application (SPA) approach is so popular these days. You have the leeway of having your SPA store the data locally, and it makes the web service calls to get any additional data it needs.

Another option is to simply cache data that would be repeatedly requested for the duration of one request.

The bottom line is that you need to think through the impacts of your design decisions, and do enough design so that you can confidently move forward in a particular direction.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.