The “Give Me Two Days” Learning Strategy
Today an engineer told me about his plans for the weekend. They were going to take a crash course in Java and Spring Boot.
The kind that promises you will “cover the essentials” of an entire framework ecosystem in a few hours, usually with a very confident youtube instructor and a progress bar that moves at an inspiring pace.
I told them that might not be the best plan. Not because learning is bad. Learning is always good.
But because the plan itself revealed a small misunderstanding about where the actual difficulty lies.
To be fair, the frustration that triggered this idea was real.
They had been working on a piece of an application and later realised there were some issues they could have spotted earlier. You know the situation.
You look at a block of code and something feels… off. But you can't immediately explain why.
Later, after someone points it out - or the behaviour becomes obvious - you look back and think:
“How did I not notice this earlier?”
Their conclusion was simple: he needed to learn the framework better. Which is a very common reaction in software development.
Something goes wrong → we assume the tool is the problem → we try to learn the tool faster.
And to be fair, this wasn’t the first time I had heard a version of this plan. Some time ago another engineer, still early in their journey through larger systems, came with a carefully designed two-week training route.
It had a schedule, a list of libraries, and a surprisingly ambitious timeline. By the end of those two weeks, according to the document, they would have covered half the modern Java ecosystem.
The problem was that most of that route focused on tools and libraries, not on the foundations underneath them.
Which is understandable. Libraries feel concrete. Frameworks feel productive. They promise visible progress.
But the thing is: the code that didn’t make sense would not suddenly make sense if it had been written in Spring Boot, Quarkus, Micronaut, plain Java, C#, or C# with .NET.
Confusing code has a remarkable ability to remain confusing across frameworks.
And the skill required to recognise it earlier usually has very little to do with crash courses.
Frameworks Are Just Fancy Packaging
As referred, the common assumption in these situations is that the missing piece must be the framework.
If the system uses Spring Boot, then understanding Spring Boot better should make the system easier to understand.
But frameworks like Spring Boot are not the system. They are an abstraction layer over problems engineers have been solving for decades:
Dependency injection. Configuration management. Application lifecycle. HTTP routing. Persistence. Messaging.
Which is great. But it also creates a small illusion: it makes it look like the complexity lives in the framework.
In reality, the complexity usually lives outside it.
There is another trap hidden here as well: sometimes concepts appear to change meaning depending on the ecosystem you are working in. Take something like a “queue.”
In embedded systems, a queue might be a small in-memory structure used to pass messages between tasks or threads.
In web applications, someone says “queue” and suddenly they mean RabbitMQ, Kafka, or some distributed messaging system moving events between services.
Different scale. Different guarantees. Same idea: a buffer that decouples producers from consumers.
Frameworks and platforms wrap these ideas with different tools, terminology, and levels of complexity. It can feel like you are learning a completely new concept, when in reality you are seeing the same one operating at a different scale.
When you are reading code that doesn’t make sense, the issue is rarely that you forgot how a Spring annotation works. It is much more likely that you are dealing with unclear responsibilities, tangled logic, hidden assumptions, or design decisions that were never properly explained.
A crash course can show you that @Service, @Repository, and @Controller exist. It can show you roughly where they go.
What it rarely explains is what those annotations actually trigger, why the separation exists, or when the design itself is the real problem.
It also cannot teach you why a piece of business logic ended up in the wrong layer, why two modules depend on each other in surprising ways, or why a seemingly simple change suddenly affects five different parts of the system.
Frameworks do not eliminate design problems — they simply give you nicer tools to build them.
Tutorials Teach the Hammer. Not When to Use It.
Tutorials are exactly that: instructions on how to use a tool. They show you the toolbox.
“Look,” they say, “here is the hammer. Here is the screwdriver. Here is the wrench. Here is the power drill.”
Then they demonstrate.
You use the hammer to hammer. Usually that happens when you have a nail. They might even show you a better way to hold the hammer, or how to hit the nail without smashing your thumb. All useful things.
What they rarely discuss is whether you should be using the hammer at all.
- Is the wall made of wood?
- Is it concrete?
- Is it safe to put nails there?
- Is there already a pipe behind that wall?
And yes, hammers can also be used to destroy things. But let’s not destroy that master wall.
Tutorials are very good at showing how tools work. They are much less interested in explaining when those tools should exist in the first place.
If you need to solve a very small problem, a tutorial is perfect. You follow the steps, you get a result, everyone is happy. But if you want to build a house, knowing how to swing a hammer is not enough.
You need to understand foundations.
Ideally, university or any other formal training would already have introduced many of these concepts.
Dependency injection. Design patterns. Architecture principles. Separation of concerns.
But let’s be honest: without some experience, these words often exist as concepts in a void. You read about them. You memorise definitions. You might even pass an exam about them.
And then you start working on real systems and realise you have no idea what any of it actually looks like in practice.
Because understanding usually comes in a different order.
First you experiment. You write code. You break things. You copy examples. You follow tutorials. You try frameworks. You build small things that work — and sometimes things that really shouldn’t.
At that stage learning is messy and unstructured. And that’s fine. In fact, it is often necessary.
And that’s fine. In fact, it is often necessary. You see the same problems. The same shapes in the code. The same attempts to organise behaviour. And then the foundations become important again.
It’s the Same Idea Wearing a Spring Jacket
If you understand what Dependency Injection and Inversion of Control are, then Spring Boot's @Autowired is not mysterious at all.
The same idea appears everywhere.
-
@Injectin Java EE or Quarkus. - The DI container in C# with .NET.
Different frameworks, same principle.
The framework did not invent the idea. It simply packaged it.
The same happens with other things you will encounter in the Spring ecosystem.
Once you understand Decorator and Proxy patterns, annotations like @Transactional or @Async become much easier to reason about. They behave like decorators: they add behaviour around a method call. Spring simply implements that layering with proxies and interception instead of manual wrapper objects.
"HandlerInterceptor and filters?": That is just Chain of Responsibility wearing a Spring jacket.
So yes — if you are going to work with Spring Boot, you should absolutely learn Spring Boot. But it becomes much easier to learn when the foundations are already in place. And those foundations also make it much easier to move between frameworks later.
Because once you know what problem you are trying to solve, the question becomes simple:
"How do I do this here?"
You need native queries? You understand the trade-offs, so you search: how do I do this in Spring Boot?
You want retries because a service call might fail? You understand the use case, so you look at the multiple ways Spring provides retries — and there are many.
Which is another reason why foundations matter: ecosystems tend to offer a lot of ways to do the same thing.
And then there is unit testing. You'll ask how to solve that with SpringBoot and someone will inevitably say:
"Let's use
@SpringBootTest."
Ah! Trick question. You usually don't use Spring Boot for unit tests. @SpringBootTest is for component / integration tests.
But there are also Test Slices, which, are indeed, mainly a Spring Boot concept, but you don’t need to worry about them until you understand what kind of tests you actually want to write.
See? Foundations.
Worst case scenario: you discover the framework does not actually solve that particular problem for you. Then you reach for a library — or you implement it yourself. But because you understand the concepts, you can still do it.
If you want a place to start building those foundations,
- Refactoring Guru is excellent for learning design patterns.
- Venkat Subramaniam is a fantastic speaker for explaining concepts clearly.
- The Java YouTube channel is great to keep up with the evolution of the platform.
- Some of the classics are still worth reading — Martin Fowler, Robert C. Martin, Sam Newman.
- Fundamentals of Software Architecture is also a great book.
And the Spring ecosystem itself has some excellent educators as well. Josh Long and the Spring team often explain not just how to use the tool, but the ideas behind it. Which is the important part.
And yes, tools like Claude, ChatGPT, Gemini and friends can also be very helpful for learning these concepts — as long as you know how to ask the question.
But that is also the catch. Knowing how to phrase the question usually means you already understand the foundations you are asking about. Which is why I still tend to recommend the other sources first.
Top comments (0)