"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.