Question

I know lazy loading is required when an expensive database call is being made. It would make sense using lazy loading in this example. The below example is in the context of asp.net so it's thread safe.

private list<Customer> _AllCustomers;
public list<Customer> AllCustomers {
get {
    if (_AllCustomers == null) {
        _AllCustomers = ExpensiveDataCall();
    }

    return _Customers;
}
 }

Even if it's just instantiating an object that is used in multiple places, I always use lazy loading. Consider the following example:

private _Customer;
public Customer Customer {
get {
    if (_Customer == null) {
        _Customer = new Customer;
    }

    return _Customer;
}
 }

Recently someone told me that lazy loading is only required for expensive database calls. Is that right? I thought every time an object is instantiated memory increases(apologize for the terminology. I don't have lot of technical knowledge.)

Was it helpful?

Solution

There's an additional thing you may want to take into account besides the sheer speed factor.

The code itself. And it's maintainability.

  • Does this kind of lazy loading make the code slower to write, or harder to understand and change?
  • Does it make the architecture more complex that it needs to be?

Some examples follow.


if (_AllCustomers == null) {
    _AllCustomers = ExpensiveDataCall();
}

return _AllCustomers; // Was: _Customers, not sure if by design.

Now, think of a scenario where you've read the AllCustomers attribute once already and then made some changes that could relate to that data. How does the caller get a fresh list of customers should it need one?

Can it somehow force nullify _AllCustomers to make the ExpensiveDataCall() happen again? Should it even know about the fact that the data in _AllCustomers may be old by now?

You can always create an additional method RefreshAllCustomersData(), or similar, but that adds the complexity of your code.

This, of course, may not be a problem in your application. It depends on the overall architecture. And even if it is, the solution to refresh may very well be suitable. It's still something to consider.


Even more simple scenarios, like the one you really were interested in, could create additional overhead for a programmer, if not to the application itself.

if (_Customer == null) {
    _Customer = new Customer;
}

return _Customer;

What happens, if a programmer, doing a class, does accidentally forget to check for null and create a new object, and only just returns null? It probably won't take too many seconds to notice, but it could.

When it comes to coding styles, this is an additional thing to remember and apply to each and every similar class. Having, for instance, only couple of model classes that follow this convention, could be confusing.

Furthermore, that's couple of extra lines that you perhaps could do without. At least, up until the point that you run your application with profiler and do note that adding lazy loading to certain places really do improve performance in a noticeable way. Less code means there's less to read and less to understand.

However, as with the first example, the practicality of this, too, depends. If you do know that you have performance culprits that go away by doing lazy loading on some spesific classes, go for it.

It is still useful to measure how much of an impact they are making, before making the decision. And whenever you form a solid convention, stick to it.


tl;dr: While lazy loading is useful tool for improving performance, it is not always required. That's because there are other factors to consider, too. Namely, maintainability of the code.

OTHER TIPS

IMHO Lazy loading is a pattern in your list of design choices. There is no "always" or "never" .. more the question: when should I and when shouldn't I.

Way back when I used to always have lazy loading for most things, these days I rarely use it, preferring instead to load "a good amount" (more formally known as a "bounded context") of several objects and their associated collected (eg Invoice and its line items) would be suitable for a single "big load" without any lazy loading being used.

That said if I'm building a parts system for an aircraft I may choose to lazy load sub assemblies if the user decided they need to "drill down further" into what I have presented them on the screen rather than wait for all 100,000 parts to come back before the user can do anything.

Which brings me to my "rules of thumb".

  • If I'm going to show a screen (or page) of data to the user when they load up, then I do a "single big grab".
  • If the screen enables drill down (like a tree view or scrolling list) then I will load what is visible + 1 level / screen so the user has some "play" when they start to scroll or start to drill down. The next block I will lazy load when I think the user has either directly asked for or has got "close enough" that they are about to ask for it.

The basic idea is that on average you should load as much data as possible without the user noticing that they are waiting for data to load (<1 sec is ideal).

When a user isn't involved then your consideration becomes "overall processing time" for a batch from source (database) > loading > processing > end result > final resulting storage or action. You want to load as much as

In your example:

Loading every customer for a small business system is probably ok (<100 or so) to take the hit and do it upfront, otherwise I would lazy load.

Loading and individual customer, assuming there is a good chance it is going to be used by the screen/process, I would do it upfront because transfer across the wire twice is likely to be more of a time lag than loading the customer along with other stuff on the server.

Your question: "does it consume memory"

Answer: Yes it does, every variable you use consumes some (usually not much) memory.

Better questions to ask:

  1. do you care about the amount of memory it is taking up MORE than having the information available for the user without lag?

Answer: the larger the amount of "stuff" being loaded the more likely you are to use lazy loading.

  1. what is the time delay involved in doing the lazy loading and is it done at a point where the user cares about the time?

Answer: by example If you show the user something first like the header or summary details and then you lazy load in all of the detail results the user doesn't usually mind waiting. If your lazy loading in every last object then the user is waiting for the Customer record + the specific invoice they care about + the total of their account + the transaction records + the line items for the invoice then you would likely choose to forward load Customer + Specific Invoice + Total of their account and then lazy load the transaction records ... the invoice line items would be a call based on your use case as to your needing to lazy load or advance load.

  1. what are the costs (memory, lag time, network and database usage) associated with a "load"?

Answer: It depends. Everything on 1 machine, probably doesn't matter much, number of hits to the database will likely be your bottleneck. Client/server its probably time frame of the database query, web server is more likely network transfer followed by database that is the issue. Each one will move the goal posts as to where the costs are that you actually need to worry about.

Licensed under: CC-BY-SA with attribution
scroll top