Every engineering team knows the tension: do you fix the architecture or ship the workaround? When our mocking library was deprecated, the "right" answer was probably a full-scale refactor to dependency injection across 13,000 Java files. The practical answer was a pattern our team hadn’t seen documented anywhere—singleton swapping. Brendan Boyd walks through the pattern, the tradeoffs, and why they were worth it. https://lnkd.in/gfrJpY26
Nextworld®’s Post
More Relevant Posts
-
🔥 Part 2 of the series is live: We just implemented @Autowired from scratch. Not just reading about it. Actually building it. Most Java developers use Spring every day — @Component, @Autowired, @Transactional — without ever understanding what's happening underneath. The answer to all of it is one API: Java Reflection. In this series, we use Reflection as the lens AND the tool. Every concept we cover, we immediately apply to build a real piece of the framework. Theory and implementation, side by side. By the end, you won't just know how Reflection works. You'll know how frameworks think. Second blog is live now 👇
To view or add a comment, sign in
-
I hit a strange realization today. Not a new concept. Not a new framework. Just something I’ve already used in production. But still… *I couldn’t explain it cleanly. We often say “I know this.” But do we really? Today’s trigger was a simple API design scenario in Spring Framework: 👉 Upload a file + send structured JSON data in the same request Sounds basic, right? But when I tried to break it down clearly— the *why*, the *how*, the *right annotation*— there was hesitation. --- Then the clarity came back: * `@RequestParam` → key-value inputs * `@PathVariable` → resource identity * `@RequestBody` → pure JSON payload * `@RequestPart` → **multipart boundary where file + structured data meet That moment reminded me of something deeper: > “Exposure creates familiarity. > But only articulation proves understanding.” In real systems, this gap shows up everywhere: * You’ve seen the pattern, but can’t justify it * You’ve fixed the bug, but can’t explain root cause * You’ve used the annotation, but don’t know *why it exists* At scale, this matters. Because senior engineering is not about: ❌ Writing more code It’s about: ✔ Explaining decisions clearly ✔ Designing with intent ✔ Debugging with first-principles thinkin --- **Today wasn’t about learning something new. It was about realizing what I hadn’t fully understood.** And that’s a different kind of progress. #SoftwareEngineering #Java #SpringBoot #SystemDesign #Backend #EngineeringMindset
To view or add a comment, sign in
-
Day 7: Mastering Dependency Injection Architectures in Spring 🚀 I’m officially one week into my Spring Framework journey! Today was a deep dive into the core of how Spring manages object dependencies. Understanding the "How" and "When" of Dependency Injection (DI) is a game-changer for writing clean, maintainable code. Here are my key takeaways from today’s session on Setter vs. Constructor Injection: 🔹 Setter Injection: Uses <property> tags in XML and requires setter methods in your bean class. Pro-tip: This is the preferred choice when your bean has a large number of properties (e.g., 10-12), as it avoids creating massive, unreadable constructors. 🔹 Constructor Injection: Uses <constructor-arg> tags and requires a parameterized constructor. Pro-tip: This is ideal for mandatory dependencies or when you have only a few properties (e.g., 2-3) to keep your code concise. ⚠️ Did you know? If you configure both Setter and Constructor injection for the same property, Setter Injection wins. This is because the IOC container first creates the object via the constructor and then calls the setter method, effectively overriding the initial value. 🛠️ Moving Toward Modern Configs: I also explored XML + Annotation-driven configurations. By using <context:component-scan> and the @Autowired annotation, we can let Spring handle the heavy lifting of injection automatically on fields, setters, or constructors. This significantly reduces the boilerplate XML code! Every day, the "magic" of Spring becomes a little more clear. Onward to Day 8! #SpringFramework #JavaDeveloper #BackendDevelopment #LearningJourney #SoftwareEngineering #DependencyInjection #CodingCommunity #TechLearning
To view or add a comment, sign in
-
I deleted a feature. ~500 unused symbols in the codebase. Now I needed to find which ones were new - and mine. A/B rollout done, losing branch goes. Easy - until you're deleting an entire core feature. You can't just remove the Fragment and the ViewModel - you'll immediately get a ton of unused entities. Think about JetBrains' Inspect Code - and yes, it's the solution. But not when your symbols are buried among 500+ other unused ones. And when you realize you can't delete them - some are actually required for future use, some belong to a feature that's being merged in parts, some are legacy, yes, but that's a mass cleanup - a separate task. That's the reality of a large codebase with parallel development. Git diff, grep, detekt, Lint - none of them catch transitive orphans across all visibility levels. I needed full-project analysis. Wait, what if we just diff the Inspect Code results? But how? There should be an export option... And turns out there is. So the plan: run Inspect Code, export XML. Remove the feature code. Run Inspect Code again, export to a different XML. Diff the two - the new unused symbols are the ones your changes created. For the diff I wrote a simple Python script: parse both XMLs, extract symbol name + file path, build two sets, compare. One pass almost always isn't enough, because of transitive dependencies. So I run the whole cycle again after cleanup. And again. Until the diff comes back empty. A full inspection takes 15-30 seconds on my M4 Pro, so it's not a bottleneck. Result: 12 modules, ~60 files, ~100 symbols cleaned up in half a day - without the risk of missing a dependency chain. Build green, tests passing after every cycle. PR approved. What about you - do you diff static analysis reports, or is there a better way I'm missing?
To view or add a comment, sign in
-
-
🚀 Day 16 – ClassLoaders: Architecture View If JVM is the engine, ClassLoaders are the gatekeepers — responsible for loading every .class into memory exactly when needed. Understanding ClassLoader architecture helps you debug class-not-found issues, memory leaks, shading conflicts, and container-based classpath problems. 🔍 How Class Loading Works JVM uses a hierarchical delegation model: 1️⃣ Bootstrap ClassLoader Loads core Java classes (java.*) Part of the JVM (native) 2️⃣ Extension / Platform ClassLoader Loads classes from $JAVA_HOME/lib/ext or platform modules 3️⃣ Application / System ClassLoader Loads everything from your classpath or app’s JARs ➡️Custom ClassLoaders Used by app servers, frameworks, plugin systems (Tomcat, OSGi, Spring Boot Layers) 🧠 Key Architecture Concepts ✔ Parent Delegation Model Child → Parent first. Prevents overriding core Java classes (security). ✔ Shadowing / Overriding Custom loaders can break delegation intentionally (OSGi, plugin engines). ✔ Namespace Isolation Each ClassLoader has its own namespace — Same class name loaded by two loaders = treated as different classes. ✔ Hot Reloading & Dynamic Loading Custom loaders allow: - Reloading modules - Loading JARs at runtime - Containerized class isolation 🎯 Why Should Developers/Architect Know This? - Fixing ClassNotFoundException, NoClassDefFoundError, LinkageError - Designing microservice modular architecture - Understanding how frameworks like Spring Boot, Quarkus, Tomcat, Jetty,Hadoop manage classes - Optimizing startup time (JVM warmup, classpath scanning) #Java #Microservices #ClassLoaders #JVM #100DaysofJavaArchitecture
To view or add a comment, sign in
-
-
#StopIgnoring What Happens After You #Click 'Run' Mastering #JVM Architecture is not just an interview checkbox. It is the single most important skill for writing #HighPerformance, #MemoryEfficient code. If you are tired of debugging OutOfMemoryError or dealing with random slowdowns, it’s time to peek under the hood. Here is the essential breakdown of the 3 Core Pillars: 1. Class Loader Subsystem (The Doorman) Your application starts here. This system finds, validates, and prepares your compiled .class files for memory. 2. Runtime Data Areas (The Memory) This is where everything lives, divided into specific zones: Heap: The Big Bucket. Where ALL objects are created. This is where the Garbage Collector lives! (Manage this well to avoid application pauses). Stack: The Workbench. Stores local variables and tracks method execution. Every single thread gets its own, private stack. Method Area: The Library. Where class structures, method data, and static variables reside. 3. Execution Engine (The Muscle) The part that actually runs your code, featuring: Interpreter: Starts fast, executing bytecode one line at a time. JIT (Just-In-Time) Compiler: Monitors "hot" (frequently used) code and compiles it into super-fast native machine code. Pro-Tip for Java Architects: Performance issues rarely start in the code they start in the Heap. Master your understanding of how the Garbage Collector (GC) reclaims that memory to prevent application-wide latency. Key Takeaway: You don’t need to know the entire JVM source code, but understanding how it manages your resources will make you a better architect. What tools do you use to peek under the hood? Are you a VisualVM fan, a JConsole loyalist, or do you prefer production APMs like Prometheus/Datadog? Let's discuss! #Java #JVM #Programming #SoftwareEngineering #Performance #CodingTips #BackendDevelopment
To view or add a comment, sign in
-
-
🧠 LeetCode POTD — From TLE to Optimized Thinking 3488. Closest Equal Element Queries At first, the approach felt straightforward. For each query: 👉 Start from the given index 👉 Expand left and right (circularly) 👉 Find the closest same element ━━━━━━━━━━━━━━━━━━━ 💥 The problem? This works… but doesn't scale. If there are q queries and n elements: → Each query can take O(n) → Total = O(n × q) 👉 This leads to TLE for large inputs. ━━━━━━━━━━━━━━━━━━━ 💡 So what's the issue? We are repeating the same work again and again for every query. ━━━━━━━━━━━━━━━━━━━ 📌 Better Approach: Preprocess the array. 👉 Use a map: value → list of indices Example: nums = [1, 2, 1, 3, 1] → 1 → [0, 2, 4] Now for each query: Get all indices of that value If only one occurrence → answer = -1 Else: 👉 Use binary search to find the closest index 👉 Check neighbors (left & right) 📌 Since the array is circular: Distance = min(|i - j|, n - |i - j|) ━━━━━━━━━━━━━━━━━━━ 💡 Complexity now: → Preprocessing: O(n) → Each query: O(log n) 👉 Total: O(n + q log n) ━━━━━━━━━━━━━━━━━━━ 📌 What I liked about this problem: The solution isn't complicated. The key is realizing: 👉 "This is not a single query problem." Once you see that, the shift from brute force → optimized becomes obvious. ✅ Sometimes optimization is not about faster code ✅ It's about not repeating the same work Curious if someone solved it differently 👀 #LeetCode #DataStructures #ProblemSolving #SoftwareEngineering #DSA #C++ #Java #SDE
To view or add a comment, sign in
-
-
Great to see union types finally coming to C# (in June). It can be used very effectively in Result Pattern. Here's a link to the type. https://lnkd.in/eHx9b-hx A definition of the Result Pattern is as follows: The Result Pattern is a design pattern used in software development to handle the outcome of an operation—specifically success or failure—in a structured and explicit way. Instead of throwing exceptions for expected business failures (like "User Not Found"), a method returns a Result object that encapsulates the success status, the actual data (if any), and error details. namespace YourProject.Something.Folder { public class BasicResponse { public int Status { get; set; } public object? ResponseObject { get; set; } public string Message { get; set; } public BasicResponse(int status, object? responseObject = null) { Status = status; ResponseObject = responseObject; Message = "Success!"; } } }
To view or add a comment, sign in
-
I was building filtering for financial records in my backend. Date range. Category. Amount range. User scope. All optional. All combinable. I started with hardcoded query logic using if-else conditions for different filter cases. It got messy fast. Every new filter meant rewriting existing logic. At one point, the queries looked like they were never meant to be read again. So I scrapped it. I implemented the Specification pattern using Spring Data JPA. Each filter became an isolated, composable predicate. At runtime, only the active ones combine into a single query. No hardcoding. No duplication. Small change in approach. Big impact on scalability and future scope. Now, adding a new filter is just one addition. Existing logic doesn't change. This is the Open/Closed principle from SOLID in practice, open for extension, closed for modification. Each Specification also owns exactly one filter concern. Single Responsibility, naturally enforced. The filtering layer went from something I avoided touching to something I can extend confidently, without regression risk. Interesting how backend complexity shifts as systems grow: performance → security → maintainability. This was firmly the third. #Backend #Java #Maintainability #SOLID #LearningInPublic #SWE
To view or add a comment, sign in
More from this author
Explore content categories
- Career
- Productivity
- Finance
- Soft Skills & Emotional Intelligence
- Project Management
- Education
- Technology
- Leadership
- Ecommerce
- User Experience
- Recruitment & HR
- Customer Experience
- Real Estate
- Marketing
- Sales
- Retail & Merchandising
- Science
- Supply Chain Management
- Future Of Work
- Consulting
- Writing
- Economics
- Artificial Intelligence
- Employee Experience
- Workplace Trends
- Fundraising
- Networking
- Corporate Social Responsibility
- Negotiation
- Communication
- Engineering
- Hospitality & Tourism
- Business Strategy
- Change Management
- Organizational Culture
- Design
- Innovation
- Event Planning
- Training & Development