June 25, 2025

๐Ÿ”ข Mastering Relative Sorting in Java (With Java 8 Best Practices)

Sorting an array based on another array's order is a popular coding problem seen in interviews and real-world systems where custom sorting logic is required.


๐Ÿงฉ Problem Statement

You're given two arrays:

  • arr1: The array you need to sort.

  • arr2: Specifies the relative ordering of some elements.

๐Ÿ“Œ Sort Rules:

  1. Elements from arr1 that are in arr2 appear first, in the same order as in arr2.

  2. Remaining elements (not in arr2) are sorted in ascending order.


✅ Example

Input:
arr1 = [2,3,1,3,2,4,6,7,9,2,19]
arr2 = [2,1,4,3,9,6]

Output:
[2,2,2,1,4,3,3,9,6,7,19]

๐Ÿงช Approach 1: Counting Sort (Optimal if Range is Known)

✅ Code:

public int[] relativeSortArray(int[] arr1, int[] arr2) {
    int[] count = new int[1001]; // assume elements are in 0–1000 range
    for (int num : arr1) count[num]++;

    int[] result = new int[arr1.length];
    int i = 0;

    for (int num : arr2)
        while (count[num]-- > 0)
            result[i++] = num;

    for (int num = 0; num < count.length; num++)
        while (count[num]-- > 0)
            result[i++] = num;

    return result;
}

✅ When to Use:

  • You know the range of input (e.g., 0 to 1000).

  • Performance is critical (time complexity: O(n + m + k)).

  • Memory usage is acceptable for fixed range.

๐Ÿง  Tips:

  • Preallocate frequency arrays if range is predictable.

  • Avoid using this for values outside a known range (e.g., negative numbers, large integers).


๐ŸŒŸ Approach 2: Java 8 Functional Solution (Elegant & Flexible)

✅ Code:

import java.util.*;
import java.util.stream.Collectors;

public class Solution {
    public int[] relativeSortArray(int[] arr1, int[] arr2) {
        Map<Integer, Integer> indexMap = new HashMap<>();
        for (int i = 0; i < arr2.length; i++) indexMap.put(arr2[i], i);

        List<Integer> list = Arrays.stream(arr1).boxed().collect(Collectors.toList());

        list.sort((a, b) -> {
            if (indexMap.containsKey(a) && indexMap.containsKey(b))
                return Integer.compare(indexMap.get(a), indexMap.get(b));
            else if (indexMap.containsKey(a))
                return -1;
            else if (indexMap.containsKey(b))
                return 1;
            else
                return Integer.compare(a, b);
        });

        return list.stream().mapToInt(Integer::intValue).toArray();
    }
}

✅ When to Use:

  • You want a cleaner, more readable solution.

  • The input range is unknown or unbounded.

  • You’re working in a modern Java codebase that uses Streams and Lambdas.


๐Ÿง  Best Practices & Tips

Practice Tip
๐Ÿ”ข Choose Right Approach Use counting sort for known integer ranges. Use Java 8 functional approach for readability and flexibility.
♻️ Avoid Magic Numbers Use Integer.MAX_VALUE or define range constants instead of hardcoding 1001.
๐Ÿ” Handle Edge Cases Always account for: duplicates, missing values in arr2, or values in arr2 not present in arr1.
⚙️ Immutable Data Prefer working with immutable streams when functional clarity matters.
๐Ÿ”„ Convert Safely Use boxed() and mapToInt() to safely convert between primitives and wrappers.
๐Ÿš€ Optimize for Large Input Counting sort is more performant than stream sorting when input size is large and value range is small.
๐Ÿงช Unit Testing Cover edge cases like arr2 being empty, all values in arr1 being outside arr2, etc.

๐Ÿ“š Summary

Feature Counting Sort Java 8 Functional
Input Range Required ✅ Yes (e.g., 0–1000) ❌ No
Duplicates ✅ Handled ✅ Handled
Readability ❌ Medium ✅ High
Performance ✅ Faster for small range ❌ Slightly Slower
Suitable for Interviews ✅ Yes ✅ Yes (bonus if explained well)

๐Ÿง‘‍๐Ÿ’ป Final Thoughts

Both approaches are valid and useful depending on your context:

  • For interview coding rounds, start with the counting sort for performance, then mention the Java 8 version as a cleaner alternative.

  • For production code, prefer the Java 8 solution unless performance is critical and the input range is tightly controlled.

June 16, 2025

AWS Lambda vs AWS Step Functions: Choosing the Right Serverless Tool

 In the world of serverless computing, two of the most powerful and widely used services offered by AWS are Lambda and Step Functions. While both serve critical roles in modern application development, understanding their strengths, limitations, and when to use each is key to building efficient and scalable systems.


What is AWS Lambda?

AWS Lambda is a compute service that lets you run code without provisioning or managing servers. It executes your code only when needed and scales automatically.

Key Features:

  • Supports multiple programming languages (Node.js, Python, Java, etc.)

  • Triggered by events from AWS services like S3, API Gateway, DynamoDB

  • Ideal for short-lived, stateless functions

  • Pay-per-use billing model (based on number of requests and execution time)

Common Use Cases:

  • Resizing images uploaded to S3

  • Backend APIs

  • Real-time file processing

  • Lightweight ETL jobs


What are AWS Step Functions?

AWS Step Functions is an orchestration service that enables you to coordinate multiple AWS services into serverless workflows. It uses a state machine model to define and manage each step.

Key Features:

  • Define workflows in JSON or YAML

  • Visual workflow builder (Workflow Studio)

  • Built-in error handling, retries, and parallelism

  • Integrates with over 200 AWS services directly

  • Two types: Standard (long-running workflows) and Express (high-throughput, short-lived workflows)

Common Use Cases:

  • Orchestrating microservices

  • Data pipelines

  • Approval workflows

  • Long-running business processes


Lambda vs Step Functions: A Comparison

Feature AWS Lambda AWS Step Functions
Purpose Execute code Orchestrate workflows
Execution Time Limit Up to 15 minutes Up to 1 year (Standard), 5 mins (Express)
State Management Manual Built-in
Error Handling In-code try/catch Declarative Retry/Catch per state
Parallel Execution Manual logic required Built-in Parallel state
Visual Debugging Logs only (CloudWatch) Full execution trace and workflow map
Best For Single, short tasks Coordinating multi-step workflows

When to Use Lambda

Use AWS Lambda when you:

  • Need to perform a single task in response to an event

  • Require fast and lightweight processing

  • Don't need to manage state between executions

  • Want simple, cost-effective compute


When to Use Step Functions

Use AWS Step Functions when you:

  • Need to coordinate multiple AWS services or Lambda functions

  • Require visual monitoring and debugging

  • Want built-in error handling and retry logic

  • Are building long-running or complex workflows


Real-World Example

Scenario: A photo processing pipeline

With Lambda only: You’d need to manage invocation of each processing step (e.g., resizing, watermarking, storing) manually, handle retries and errors in code.

With Step Functions: Each step is defined as a state. You gain clear visibility, parallel processing (e.g., for different sizes), and built-in retries.


Conclusion

Both AWS Lambda and Step Functions are integral to serverless development, but they shine in different areas. For independent, simple functions, Lambda is the go-to choice. For multi-step, error-prone, or complex processes, Step Functions provide powerful orchestration capabilities.

Understanding when to use each will help you design better, more scalable, and maintainable serverless architectures.

AWS Lambda vs AWS Step Functions: Choosing the Right Serverless Tool

In the world of serverless computing, two of the most powerful and widely used services offered by AWS are Lambda and Step Functions. While both serve critical roles in modern application development, understanding their strengths, limitations, and when to use each is key to building efficient and scalable systems.


What is AWS Lambda?

AWS Lambda is a compute service that lets you run code without provisioning or managing servers. It executes your code only when needed and scales automatically.

Key Features:

  • Supports multiple programming languages (Node.js, Python, Java, etc.)

  • Triggered by events from AWS services like S3, API Gateway, DynamoDB

  • Ideal for short-lived, stateless functions

  • Pay-per-use billing model (based on number of requests and execution time)

Common Use Cases:

  • Resizing images uploaded to S3

  • Backend APIs

  • Real-time file processing

  • Lightweight ETL jobs


What are AWS Step Functions?

AWS Step Functions is an orchestration service that enables you to coordinate multiple AWS services into serverless workflows. It uses a state machine model to define and manage each step.

Key Features:

  • Define workflows in JSON or YAML

  • Visual workflow builder (Workflow Studio)

  • Built-in error handling, retries, and parallelism

  • Integrates with over 200 AWS services directly

  • Two types: Standard (long-running workflows) and Express (high-throughput, short-lived workflows)

Common Use Cases:

  • Orchestrating microservices

  • Data pipelines

  • Approval workflows

  • Long-running business processes


Lambda vs Step Functions: A Comparison

Feature AWS Lambda AWS Step Functions
Purpose Execute code Orchestrate workflows
Execution Time Limit Up to 15 minutes Up to 1 year (Standard), 5 mins (Express)
State Management Manual Built-in
Error Handling In-code try/catch Declarative Retry/Catch per state
Parallel Execution Manual logic required Built-in Parallel state
Visual Debugging Logs only (CloudWatch) Full execution trace and workflow map
Best For Single, short tasks Coordinating multi-step workflows

When to Use Lambda

Use AWS Lambda when you:

  • Need to perform a single task in response to an event

  • Require fast and lightweight processing

  • Don't need to manage state between executions

  • Want simple, cost-effective compute


When to Use Step Functions

Use AWS Step Functions when you:

  • Need to coordinate multiple AWS services or Lambda functions

  • Require visual monitoring and debugging

  • Want built-in error handling and retry logic

  • Are building long-running or complex workflows


Real-World Example

Scenario: A photo processing pipeline

With Lambda only: You’d need to manage invocation of each processing step (e.g., resizing, watermarking, storing) manually, handle retries and errors in code.

With Step Functions: Each step is defined as a state. You gain clear visibility, parallel processing (e.g., for different sizes), and built-in retries.


Conclusion

Both AWS Lambda and Step Functions are integral to serverless development, but they shine in different areas. For independent, simple functions, Lambda is the go-to choice. For multi-step, error-prone, or complex processes, Step Functions provide powerful orchestration capabilities.

Understanding when to use each will help you design better, more scalable, and maintainable serverless architectures.

June 13, 2025

๐Ÿงต Mastering Singleton Pattern in Java: volatile, synchronized, Spring Bean Scopes & Java 25 Best Practices

๐Ÿง  What is Singleton?

A Singleton ensures only one instance of a class is created and provides a global access point to it.

This is useful for:

  • Configuration classes

  • Logger objects

  • Database connection managers

  • Caching systems


๐Ÿ›‘ Problem: Thread-Unsafe Lazy Singleton

public class Singleton {
    private static Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            instance = new Singleton(); // ❌ Thread unsafe
        }
        return instance;
    }
}

This code may create multiple instances in a multithreaded environment.


✅ Proper Thread-Safe Singleton with volatile + synchronized

public class Singleton {

    private static volatile Singleton instance;

    private Singleton() {}

    public static Singleton getInstance() {
        if (instance == null) {
            synchronized (Singleton.class) {
                if (instance == null) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

⚙️ Modern Singleton Alternatives

๐Ÿ”น Static Holder Pattern

public class Singleton {
    private Singleton() {}
    private static class Holder {
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance() {
        return Holder.INSTANCE;
    }
}

๐Ÿ”น Enum-based Singleton

public enum Singleton {
    INSTANCE;
}

๐ŸŒฟ Singleton in Spring Framework

Spring beans are Singleton by default, meaning:

Only one instance of the bean is created per Spring container.

✅ Declaring a Singleton Bean (default)

@Component
public class AppConfig {
    // default scope is Singleton
}

or explicitly:

@Component
@Scope("singleton")
public class AppConfig {
}

๐Ÿ”„ Changing Bean Scope in Spring

You can control a bean’s scope using the @Scope annotation.

Available Scopes in Spring (Core)

Scope Description
singleton One shared instance per Spring context (default)
prototype A new instance is created every time it's requested
request One instance per HTTP request (Web only)
session One instance per HTTP session (Web only)
application One instance per ServletContext (Web only)
websocket One instance per WebSocket session

๐Ÿ”ง How to Change Bean Scope

@Component
@Scope("prototype")
public class ReportGenerator {
    // A new instance is returned every time it's injected
}

Or using XML (for older Spring):

<bean id="myBean" class="com.example.MyBean" scope="prototype"/>

๐Ÿงช How to Control and Verify Scope

Example Test Class:

@SpringBootTest
public class ScopeTest {

    @Autowired
    private ApplicationContext context;

    @Test
    void testScope() {
        MyBean b1 = context.getBean(MyBean.class);
        MyBean b2 = context.getBean(MyBean.class);

        System.out.println(b1 == b2 ? "Singleton" : "Prototype");
    }
}

๐Ÿ’Ž Java 25 Best Practices for Singleton

✅ Use volatile in lazy initialization
✅ Use @Scope("singleton") in Spring for explicit intent
✅ Use enum to prevent reflection/cloning
✅ Avoid heavy logic in constructor
✅ Override readResolve() if serializing
✅ Use @ThreadSafe for clarity
✅ Use JMH to benchmark Singleton performance
✅ Prefer DI-managed beans (Spring, Micronaut, etc.)
✅ Protect against classloader issues in plugins


๐Ÿ”š Conclusion

  • Use volatile and synchronized together in double-checked locking.

  • Use static inner class or enum for better control.

  • In Spring, prefer letting the container manage Singleton scope.

  • Change scope using @Scope, depending on your app needs.


✨ Summary Table

Singleton Pattern Thread-safe Lazy Init Recommended
static instance
synchronized method ⚠️
volatile + sync
Static holder ✅✅
Enum ✅✅ ✅✅✅
Spring Singleton Bean ✅✅✅

Would you like this exported as a Markdown file, HTML, or copy-ready for Medium/Dev.to?

June 12, 2025

Understanding authSession.setAction(AUTHENTICATE) and Related Settings in Keycloak Login Flows

When customizing login flows in Keycloak—especially during first login with an identity provider (IdP)—you often interact with the AuthenticationSessionModel and AuthenticatedClientSessionModel. If you’ve looked at lines like the following and wondered what they do or why they’re necessary, this blog is for you:

authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);
authSession.setClientNote(OIDCLoginProtocol.ISSUER, Urls.realmIssuer(session.getContext().getUri().getBaseUri(), realm.getName()));
authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, "openid");
authSession.setAction(AuthenticatedClientSessionModel.Action.AUTHENTICATE.name());

๐ŸŽฏ Problem Statement

In a custom login flow, particularly when modifying the first broker login flow, missing or incorrect session attributes can result in:

  • invalid_request or invalid_signature errors

  • missing id_tokens

  • broken post-login steps like account linking or consent pages

  • failure to issue access or refresh tokens

To ensure smooth interoperability between Keycloak and the OIDC protocol, it's essential to explicitly configure the authSession.


๐Ÿงช What Each Line Does and Why It Matters

1️⃣ authSession.setProtocol(OIDCLoginProtocol.LOGIN_PROTOCOL);

  • Purpose: Tells Keycloak that the current session is using the openid-connect protocol.

  • Why it's important: Without it, Keycloak might not route the request properly or issue OIDC-compliant tokens.


2️⃣ authSession.setClientNote(OIDCLoginProtocol.ISSUER, <issuer-url>);

  • Purpose: Sets the issuer for the session, which is later embedded in the id_token.

  • Why it's important: If this doesn’t match the value expected by the client, token verification will fail with an "invalid issuer" error.


3️⃣ authSession.setClientNote(OIDCLoginProtocol.SCOPE_PARAM, "openid");

  • Purpose: Specifies the OAuth2/OIDC scopes requested by the client.

  • Why it's important: The "openid" scope is required to receive an id_token. If omitted, your application won’t get identity claims.


4️⃣ authSession.setAction(AUTHENTICATE);

  • Purpose: Sets the session's current action to AUTHENTICATE, signaling Keycloak that the user is in the authentication step.

  • Why it's important:

    • Drives what Keycloak will do next (e.g., show login form, redirect to consent).

    • Affects what happens after authentication—like whether required actions or token exchange steps will run.

    • Without it, the flow can end prematurely or fail entirely.


๐Ÿงพ Available Actions in AuthenticatedClientSessionModel.Action

These enum values define what stage the user is currently in within the Keycloak login or token flow:

Action Description
AUTHENTICATE User is currently authenticating (e.g., login form, social login)
LOGGED_IN Authentication is completed successfully
REQUIRED_ACTIONS User must perform additional steps (verify email, update password, etc.)
CODE_TO_TOKEN The client is exchanging an authorization code for tokens (OAuth2 Code Flow)
OAUTH_GRANT The user is granting consent to the client for requested scopes
REGISTER User is undergoing the registration flow

These values control what happens next in the flow, which UI screens are shown, and which server-side logic gets triggered.


๐Ÿงฉ Where You Typically Use This

These session settings are commonly found in:

  • IdpCreateUserIfUniqueAuthenticator (default first-login logic)

  • Your custom Authenticator or AuthenticatorFactory when extending login flow

  • SPIs that handle custom logic during IdP login or user account creation


✅ Best Practices

  • Always set the protocol, scope, and issuer for custom login flows.

  • Set the action to match the current step (AUTHENTICATE, REGISTER, etc.).

  • Ensure you do this before token issuance or response handling steps.


๐Ÿšซ What Happens If You Skip These

Setting Without It...
setProtocol(...) Flow might not work; tokens might not be generated.
setClientNote(ISSUER) id_token may have wrong issuer → validation fails.
setClientNote(SCOPE_PARAM) No id_token, breaking OIDC login.
setAction(AUTHENTICATE) Flow breaks midway or doesn't trigger post-login handlers.

๐Ÿง  Conclusion

Customizing Keycloak login flows is powerful but requires careful handling of session metadata. These authSession configurations are not optional—they are critical building blocks for a stable and secure authentication experience.

If you're implementing a custom Authenticator or enhancing the first-broker-login flow, make sure to explicitly set these session details to avoid unpredictable errors and ensure a smooth experience for both users and client applications.

May 19, 2025

Introducing the Smart Federated Identity Hub: Next-Gen Context-Aware SSO with AI-Powered Claim Management

In today’s hyper-connected digital ecosystem, enterprises rely heavily on Single Sign-On (SSO) to streamline user access across multiple applications and services. Tools like Keycloak have become the backbone for identity and access management (IAM), offering seamless authentication and authorization experiences.

However, with great power comes great responsibility. One persistent challenge remains unresolved: How can organizations selectively share user data (claims) with different client applications in a way that respects privacy, regulatory compliance, and business-specific requirements — all without compromising user experience?


The Challenge: Balancing Data Sharing with Privacy and Security

When a user logs in through an identity provider like Keycloak, a set of claims (user attributes such as email, phone number, roles) is sent to the requesting client application. But:

  • Most current systems apply a one-size-fits-all approach, releasing identical claims to all clients.

  • This overexposure increases privacy risks and may violate regulations like GDPR, HIPAA, or India’s DPDP.

  • Different clients (e.g., HR portal vs. Marketing app) often require different subsets of user data.

  • Managing claim configurations manually for dozens or hundreds of clients quickly becomes unsustainable.

  • There’s no dynamic mechanism to factor in contextual signals like user consent, login device, location, or behavioral risk.

As businesses scale, this inefficiency creates serious security vulnerabilities and compliance bottlenecks, limiting the adoption of federated identity solutions in sensitive domains like finance, healthcare, and government.


The Vision: A Smart Federated Identity Hub

Imagine an identity hub that intelligently and dynamically controls which user claims to share with which client — powered by AI and enriched with contextual awareness.

Our proposed solution integrates:

  • Keycloak as the core identity broker

  • Custom extensions (via Keycloak SPI) that trigger an AI-powered decision engine at login

  • Real-time invocation of a GenAI model (GPT-4o mini) that assesses user, client, and contextual data

  • Dynamic claim release tailored to client-specific policies, user consent, and risk signals

  • A Consent Ledger tracking data sharing events for auditing and compliance

  • Use of MCP (Microservice Communication Protocol) for secure downstream propagation of selective claims to partner services

  • Optional Explainability UI to visualize why certain claims were shared or withheld, building trust and transparency


How It Works: Context-Aware Claim Decisions

When a user initiates an SSO login:

  1. Keycloak invokes the AI-driven ClaimsMapper SPI, passing key information about the user, client, login context, and prior consents.

  2. The AI model processes this input, referencing internal policies and learned patterns, and outputs a customized list of claims allowed for release.

  3. Keycloak releases only the allowed claims to the client’s ID token or access token.

  4. All data sharing events are recorded in the Consent Ledger for future reference.

  5. For downstream microservices needing select user data, claims are securely synced using the MCP protocol — maintaining minimal data exposure.

  6. Admins or auditors can review decision rationales in a dedicated dashboard, ensuring accountability.


Unique Value Proposition

  • Privacy-first: AI-powered data minimization enforces the principle of least privilege

  • Scalable: Automatically adapts claim sharing for hundreds of clients across multiple business units

  • Compliant: Supports evolving regulatory mandates with granular consent and audit trails

  • Explainable: Builds stakeholder confidence with transparent claim decisioning

  • Reusable: Applicable across industries from BFSI to Healthcare and SaaS


Tech Stack Overview

Component Technology
Identity & Auth Keycloak (SPI Extensions)
AI Engine GPT-4o mini (OpenAI API)
Backend Service Spring Boot + WebClient
Database PostgreSQL (Consent Ledger)
Protocol MCP (Microservice Protocol)
Deployment Docker / Calibo
Admin UI (optional) React / Thymeleaf

Sample Code Snippet: AI-Driven Claim Mapper SPI

public class AiDrivenClaimMapper implements ProtocolMapper, OIDCAdvancedClaimToTokenMapper {
    @Override
    public void transformAccessToken(TokenMapperContext context) {
        AccessToken token = context.getAccessToken();
        UserModel user = context.getUserSession().getUser();
        ClientModel client = context.getClientSession().getClient();

        Map<String, Object> inputPayload = Map.of(
            "username", user.getUsername(),
            "email", user.getEmail(),
            "clientId", client.getClientId(),
            "loginIp", context.getSession().getContext().getConnection().getRemoteAddr()
        );

        List<String> claimsToRelease = AiService.getAllowedClaims(inputPayload);

        if (claimsToRelease.contains("email")) {
            token.getOtherClaims().put("email", user.getEmail());
        }
        if (claimsToRelease.contains("phone")) {
            token.getOtherClaims().put("phone", user.getFirstAttribute("phone"));
        }
    }
}

Conclusion

The Smart Federated Identity Hub is a game-changer for enterprises looking to reconcile seamless user experience with strict data privacy and security requirements. By combining the power of Keycloak’s extensibility with AI-driven contextual claim decisions, this solution not only improves security and compliance but also future-proofs identity management for the evolving digital landscape.

If you want to explore how AI can transform identity management in your organization or need help building a privacy-first identity architecture, reach out! The future of IAM is smart, context-aware, and explainable.


Would you like me to help prepare detailed implementation guides or demo videos next?

May 14, 2025

๐Ÿง‘‍๐Ÿ’ป Why Apple SSO Doesn't Return First and Last Name After First Login (and How to Handle It)

Single Sign-On (SSO) has become the gold standard for seamless user authentication. With providers like Google, Facebook, and Apple, integrating social login has never been easier. But when using Apple SSO, many developers face a confusing issue:

After the first login, Apple no longer returns the user's first and last name.

This behavior isn't a bug — it's by design. In this blog, we’ll dive into:

  • Why Apple behaves this way

  • How it's different from Google and Facebook

  • How to fix it in your app

  • Whether you can use Apple’s private relay email for OTP/communication


๐Ÿ Why Apple Doesn’t Return Name After First Login — By Design

Apple is known for putting user privacy first, and its SSO implementation reflects that.

When a user signs in using Apple for the first time, Apple returns the given_name, family_name, and optionally the email. However, subsequent logins will not return the name again, regardless of scopes.

๐Ÿ“œ Apple Developer Docs:
“Apple only shares user information such as name and email once, during the initial authorization.”

This is intentional to:

  • Minimize personal data shared with third-party apps

  • Give users complete control over their identity

  • Ensure developers store data responsibly


๐Ÿ” Why This Is Not an Issue with Google or Facebook

Both Google and Facebook take a more traditional OAuth 2.0 approach. When requested via appropriate scopes (profile, email), they consistently return:

  • First name

  • Last name

  • Profile picture

  • Email

Feature Apple Google / Facebook
Name returned always ❌ Only on first login ✅ On every login
Email always returned ✅ Yes (if allowed) ✅ Yes
Can hide real email ✅ Yes (private relay option) ❌ No
Privacy-first approach ✅ Very strict ❌ Less strict

๐Ÿ› ️ How to Fix the Missing Name Issue

To build a robust Apple SSO integration, here’s what you should do:

✅ 1. Store the Name at First Login

After the first login, extract and persist the name in your backend.

Map<String, Object> claims = decodeJwt(appleIdToken);
String firstName = (String) claims.get("given_name");
String lastName = (String) claims.get("family_name");

if (firstName != null && lastName != null) {
    userService.saveUserName(userId, firstName, lastName);
}

๐Ÿ” 2. Fetch Name From Your DB for Later Logins

Since Apple won’t send it again, use the stored name for future user sessions:

User user = userRepository.findByAppleSub(appleSub);
String name = user.getFirstName() + " " + user.getLastName();

✏️ 3. Prompt User If Name Was Never Captured

If the name wasn’t captured during the first login (e.g., due to a bug or user canceling), prompt the user to enter it manually.


๐Ÿ“ง Can You Use Apple’s Private Relay Email for OTP and Communication?

Yes! If a user chooses “Hide My Email” during Apple SSO, Apple generates a relay address like:

randomstring@privaterelay.appleid.com

✅ You Can Send OTPs and Emails to It

Apple forwards emails sent to this relay address to the user’s actual Apple ID inbox. You can use it for:

  • OTPs

  • Welcome emails

  • Password reset links

  • Transactional notifications

Apple guarantees delivery as long as your domain is registered and emails are compliant.

๐Ÿ”’ Key Considerations

Aspect Details
Relay Validity Relay remains active while the user uses your app
SPF/DKIM Required Set up email authentication to avoid spam filtering
No Marketing Emails Stick to transactional emails; avoid promotional content
Reply-to Address Set it up if you expect users to reply

๐Ÿ“ฅ Can Users Access It?

Absolutely. Users receive emails sent to @privaterelay.appleid.com in their actual inbox, just like any other email. They typically don’t see or interact with the relay address directly.


๐Ÿงฉ Bonus: How to Detect First-Time Apple Login

You can determine if it's a first-time login based on whether given_name and family_name are present in the ID token or the user JSON payload. If they're missing, it's a returning login.


๐Ÿงญ Final Thoughts

Apple's approach to SSO is driven by a strong privacy philosophy. While it may introduce some extra work for developers, it's a positive step for user data protection.

To ensure a smooth experience:

  • Store user name on first login

  • Use Apple’s private relay email confidently for OTPs and communication

  • Respect user privacy — and be ready to ask for missing info if needed


Need Help With Apple, Google, or Facebook SSO in Spring Boot or WebFlux?
I help teams build secure and privacy-conscious SSO integrations. Reach out if you’d like a tailored solution!


Would you like this in HTML format or exported as a file for publishing?

๐Ÿš€ Micronaut vs Spring Boot: The Ultimate Cloud-Native Java Showdown (AWS Lambda, EC2, Spot Instances)

  • In the age of microservices and serverless, Java still rules — but the framework you choose can dramatically impact cost, performance, and developer experience.

This blog breaks down a practical, head-to-head comparison between Micronaut and Spring Boot, with a special focus on AWS Lambda, EC2, and Spot Instances.


๐ŸŒŸ TL;DR Summary

Criteria Micronaut Spring Boot
๐Ÿš€ Startup Time Ultra-fast (20–100ms) Moderate to slow (500ms–3s)
๐Ÿ’พ Memory Usage Low (30–60MB typical) Higher (100–300MB typical)
๐Ÿง  Dependency Injection Compile-time (AOT) Runtime (reflection-heavy)
☁️ Serverless Fit ✅ Excellent for AWS Lambda ⚠️ Possible but slower cold starts
๐Ÿ’ธ Cost Efficiency ✅ Great for Spot/Lambda ⚠️ More costly in cold-start/serverless
๐Ÿ” Ecosystem Lightweight, focused Huge ecosystem, mature integrations
๐Ÿ“‰ Disadvantages Smaller community, limited plugins Slower boot, higher memory use

๐Ÿ” 1. Architecture Difference

Feature Micronaut Spring Boot
Dependency Injection AOT (compile-time) – no reflection Runtime reflection-based
Bean Instantiation Fast, direct bytecode-generated Slower due to dynamic proxies & reflection
Native Image Support First-class (GraalVM, small images) Supported but complex and large native images

Takeaway: Micronaut was built for cloud-native from the ground up, Spring Boot evolved into it.


⚡ 2. AWS Lambda: Cold Start Matters

Aspect Micronaut Spring Boot
Cold Start Time ~20–100ms (JVM), <10ms (native) ~1–3 seconds (JVM), ~700ms (native)
Memory Footprint ~30–60MB ~150–300MB
Cost Implication ✅ Lower Lambda invocation costs ⚠️ Higher cold start costs

๐Ÿ’ฐ AWS Lambda Cost Snapshot (Monthly Estimate):

Scenario: 1 million monthly invocations, 512MB memory, 1s avg runtime

Framework Monthly Cost (USD)
Micronaut ~$4.00
Spring Boot ~$10.00

๐Ÿ‘‰ Micronaut can save 2–3x costs in cold-start-heavy use cases.


๐Ÿ’ก 3. EC2 / Spot Instances: Boot Fast, Scale Faster

Area Micronaut Spring Boot
Boot Time (EC2 restart) ~300ms ~2–5 seconds
Ideal for Spot Scaling ✅ Yes ⚠️ Less ideal due to slow start
Memory Footprint (512MB RAM) ✅ Fits easily ⚠️ May require memory tuning

EC2 Cost Snapshot (t4g.small - ₹500/month baseline):

  • Micronaut allows you to pack more services per instance (lower infra cost).

  • Spring Boot might require more EC2 nodes or larger instances = higher cost.


⚖️ 4. Disadvantages: Honest Look

❌ Micronaut Disadvantages:

  • Smaller ecosystem (e.g., fewer libraries and integrations)

  • Less community support compared to Spring

  • Learning curve due to compile-time DI model

  • GraalVM native images require careful tuning (startup vs throughput)

❌ Spring Boot Disadvantages:

  • Slower startup (problematic for Lambda/serverless)

  • Higher memory use → increased cloud cost

  • Reflection-heavy = poor native image performance

  • Runtime dependency scanning slows boot


๐Ÿงช 5. Performance Benchmark (JVM)

Metric Micronaut (JVM) Spring Boot (JVM)
Startup Time ~200–400ms ~1.5–3s
Memory Usage ~50MB ~150–300MB
Throughput (req/s) High High (with warm JVM)
Native Image Time <30ms (Micronaut native) ~500–800ms (Spring Native)

๐Ÿ“Œ Micronaut shines in startup + Lambda; Spring Boot wins for always-on services with rich dependencies.


๐Ÿงฐ 6. Ecosystem & Tooling

Category Micronaut Spring Boot
CLI / Scaffolding Yes (mn CLI) Yes (spring init)
Dev Tools Hot reload (limited), Gradle/Maven DevTools, Spring Dev Launcher
Libraries REST, gRPC, Kafka, AWS SDK Huge ecosystem, legacy & modern support
IDE Support IntelliJ, VSCode IntelliJ, Eclipse, STS, VSCode

๐Ÿ“Œ 7. Ideal Use Cases

Use Case Recommended Framework
AWS Lambda ✅ Micronaut
Short-lived background jobs ✅ Micronaut
Resource-constrained environments ✅ Micronaut
Legacy migration ✅ Spring Boot
Complex integrations (JMS, JPA) ✅ Spring Boot
Large teams with Spring skills ✅ Spring Boot

๐Ÿ”ฎ 8. What's Next: Micronaut + Galvium

Micronaut’s partnership with Galvium (an upcoming JVM runtime) aims to cut JVM cold starts down to ~10mswithout native compilation.

Galvium + Micronaut could redefine how Java works in:

  • Instant cold starts

  • Serverless

  • Autoscaling pods

It’s early, but Micronaut is future-proofing Java cloud apps.


✅ Conclusion

Summary Verdict
Cloud-native design ✅ Micronaut
Mature enterprise ecosystem ✅ Spring Boot
Fast cold start and low memory ✅ Micronaut
Best for long-running heavy apps ✅ Spring Boot
Cost-efficient for AWS Lambda/EC2 ✅ Micronaut
Easier onboarding & hiring ✅ Spring Boot

๐Ÿ“ Want More?

Would you like this blog exported as:

  • ✅ Markdown (.md)

  • ✅ HTML

  • ✅ Publish-ready Medium/Dev.to format

  • ✅ With diagrams comparing startup/memory graphs

Just say the word and I’ll generate it for you!

May 10, 2025

๐Ÿ›ก️ Understanding the Proxy Design Pattern in Java — Real-World Usage and Examples

When it comes to structural design patterns, the Proxy Pattern stands out as one of the most powerful tools for controlling access to an object, managing performance, and adding extra functionality transparently. From security to lazy loading, the proxy pattern has wide-reaching applications in modern Java development — especially in frameworks like Spring and Hibernate.

In this article, we’ll explore:

  • ✅ What is the Proxy Design Pattern?

  • ๐Ÿ” Real-world analogies

  • ๐Ÿ› ️ Types of Proxies (Virtual, Protection, Remote, etc.)

  • ☕ Java implementation

  • ๐ŸŒฑ How Spring uses proxies

  • ๐Ÿ“Š Advantages and trade-offs


๐Ÿง  What is the Proxy Pattern?

Proxy Pattern provides a surrogate or placeholder for another object to control access to it.

Think of it as a gatekeeper or middleman that decides whether or how to pass a request to the real object.

It belongs to the structural family of design patterns and is especially useful when:

  • Creating the actual object is expensive.

  • You want to control access to the real object.

  • You need to add extra behavior (e.g., logging, security) without modifying the real object.


๐ŸŽฏ Real-world Analogy

Imagine you're trying to meet a high-profile CEO. You can't just walk into their office — you go through their secretary (proxy) first, who checks your purpose, filters calls, and decides whether to forward your request.


๐Ÿงฑ Types of Proxies in Java

Type Purpose
๐Ÿ”„ Virtual Proxy Defers creation of resource-heavy objects until needed
๐Ÿ” Protection Proxy Controls access based on permissions or user roles
๐ŸŒ Remote Proxy Represents objects in a different address space (e.g., RMI)
๐Ÿ“ Logging Proxy Adds behavior like logging, caching, or performance tracking
๐Ÿงช Smart Proxy Adds extra actions (e.g., ref counting, access tracking)

๐Ÿ’ป Java Implementation — Virtual Proxy

Let's build a virtual proxy that delays the creation of a large image until it's needed.

Step 1: Create a Common Interface

public interface Image {
    void display();
}

Step 2: The Real Object

public class RealImage implements Image {
    private String fileName;

    public RealImage(String fileName) {
        this.fileName = fileName;
        loadFromDisk();
    }

    private void loadFromDisk() {
        System.out.println("Loading " + fileName);
    }

    public void display() {
        System.out.println("Displaying " + fileName);
    }
}

Step 3: The Proxy Class

public class ProxyImage implements Image {
    private RealImage realImage;
    private String fileName;

    public ProxyImage(String fileName) {
        this.fileName = fileName;
    }

    public void display() {
        if (realImage == null) {
            realImage = new RealImage(fileName); // expensive
        }
        realImage.display();
    }
}

Step 4: Client Code

public class Main {
    public static void main(String[] args) {
        Image image = new ProxyImage("test.jpg");

        System.out.println("Image created");

        image.display(); // loads and displays
        image.display(); // only displays
    }
}

Output:

Image created
Loading test.jpg
Displaying test.jpg
Displaying test.jpg

๐Ÿงฐ Spring Framework and Proxy Pattern

Spring relies heavily on proxies, especially for:

✅ AOP (Aspect-Oriented Programming)

  • Cross-cutting concerns like logging, transactions, and security are implemented using dynamic proxies (JDK or CGLIB).

✅ @Transactional

  • When you use @Transactional, Spring creates a proxy around the bean and applies transaction boundaries before and after the method call.

Example:

@Transactional
public void transferMoney(Account from, Account to, BigDecimal amount) {
    // Transactional logic
}

Here, Spring uses a proxy to manage the transaction behind the scenes.


๐Ÿ“Š Advantages of the Proxy Pattern

  • ✔️ Controls access to the real object

  • ✔️ Adds functionality without changing original code

  • ✔️ Supports lazy initialization

  • ✔️ Can improve performance and security


⚠️ Drawbacks

  • ❌ Adds extra complexity

  • ❌ Overhead if too many proxies are layered

  • ❌ Harder debugging in heavily proxied environments (especially dynamic proxies)


๐Ÿ“ฆ When to Use the Proxy Pattern

Use Case Recommended?
Lazy-loading large resources ✅ Yes (Virtual Proxy)
Security enforcement ✅ Yes (Protection Proxy)
Access to remote resources ✅ Yes (Remote Proxy)
Adding cross-cutting concerns ✅ Yes (Smart/Logging Proxy, AOP)
Overusing proxies in simple apps ❌ Avoid

๐Ÿงพ Final Thoughts

The Proxy Pattern is a powerful tool in your Java toolbox. Whether you're optimizing performance, enforcing security, or adding dynamic behavior, the proxy allows you to extend behavior transparently without touching the real business logic.

Frameworks like Spring and Hibernate make heavy use of this pattern under the hood — so understanding it is key to writing better, cleaner, and more efficient Java applications.


✨ TL;DR

  • Proxy Pattern = Surrogate for real object

  • Types: Virtual, Protection, Remote, Logging

  • Java and Spring use proxies for lazy loading, AOP, and security

  • Recommended for clean separation and controlled object access


Would you like this blog converted to Markdown, PDF, or a LinkedIn/Medium-optimized format?

๐ŸŒฟ Lazy Loading with Static Inner Class in Java — A Deep Dive Into Smart Initialization

In the world of Java performance optimization, lazy loading is a best practice when you're dealing with heavy objects or expensive computations that may not always be needed. One particularly elegant technique to achieve lazy initialization is the use of a static inner class — often underutilized, but incredibly powerful.

In this comprehensive blog, we’ll explore:

  • What lazy loading means in Java

  • How static inner classes work for lazy loading

  • Detailed comparisons with other lazy initialization techniques

  • When to use which method

  • Whether the static inner class approach is complex or not


๐Ÿ“˜ What Is Lazy Loading?

Lazy loading is a design pattern that defers the initialization of an object until it is actually needed.

Why Use Lazy Loading?

  • ๐Ÿง  Optimized memory usage: Don’t load it if you don’t use it.

  • ๐Ÿš€ Faster application startup: Defer costly operations.

  • ๐Ÿ›  Improved performance in scalable systems: Reduces bottlenecks during application bootstrapping.


๐Ÿงฑ Static Inner Classes for Lazy Initialization

What is a Static Inner Class?

A static inner class is a nested class declared with the static keyword. It does not need an instance of the outer class to be instantiated, and more importantly:

⚠️ A static inner class is not loaded into memory until it is explicitly referenced.

This makes it perfect for on-demand loading.


๐Ÿ›  Example: Singleton with Static Inner Class

public class LazySingleton {

    private LazySingleton() {
        System.out.println("Constructor called");
    }

    // Inner class loaded only when getInstance() is called
    private static class Holder {
        private static final LazySingleton INSTANCE = new LazySingleton();
    }

    public static LazySingleton getInstance() {
        return Holder.INSTANCE;
    }
}

✅ JVM Guarantees:

  • The Holder class is only loaded when getInstance() is called.

  • Class loading in Java is thread-safe, so no synchronization is needed.

  • Lazy, thread-safe, and elegant — without boilerplate.


๐Ÿ” Other Ways to Do Lazy Initialization in Java

Let’s compare the static inner class technique with other common singleton approaches:

1. Eager Initialization

public class EagerSingleton {
    private static final EagerSingleton INSTANCE = new EagerSingleton();
    private EagerSingleton() {}
    public static EagerSingleton getInstance() {
        return INSTANCE;
    }
}

✅ Simple
❌ Not lazy — instance is created even if never used


2. Lazy Initialization (Non-thread-safe)

public class LazySingleton {
    private static LazySingleton instance;
    private LazySingleton() {}
    public static LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

✅ Lazy
❌ Not thread-safe — multiple threads may create multiple instances


3. Lazy Initialization with synchronized Method

public class LazySingleton {
    private static LazySingleton instance;
    private LazySingleton() {}
    public static synchronized LazySingleton getInstance() {
        if (instance == null) {
            instance = new LazySingleton();
        }
        return instance;
    }
}

✅ Lazy and thread-safe
❌ Performance overhead due to synchronization


4. Double-Checked Locking

public class LazySingleton {
    private static volatile LazySingleton instance;
    private LazySingleton() {}

    public static LazySingleton getInstance() {
        if (instance == null) {
            synchronized (LazySingleton.class) {
                if (instance == null) {
                    instance = new LazySingleton();
                }
            }
        }
        return instance;
    }
}

✅ Lazy
✅ Thread-safe
⚠️ Slightly complex
⚠️ Requires volatile (since Java 1.5) to prevent instruction reordering


5. Static Inner Class (Best of All Worlds)

✅ Lazy
✅ Thread-safe
✅ No synchronization overhead
✅ Cleaner and easier than double-checked locking
✅ JVM handles everything


๐Ÿ“Š Comparative Table

Method Lazy Thread-safe Performance Complexity
Eager Initialization Simple
Non-thread-safe Lazy Init Simple
Synchronized Method Simple
Double-Checked Locking Medium
Static Inner Class Very Simple

๐Ÿค” Is Static Inner Class Complicated?

Not at all! It's one of the simplest and safest lazy initialization patterns in Java:

  • No need for synchronization or volatile

  • No risk of race conditions

  • Easier to read and maintain than double-checked locking

In fact, many developers consider this the go-to method for implementing lazy singletons in modern Java applications.


๐Ÿง  When Should You Use It?

✅ Use static inner class lazy loading when:

  • You want a lazy singleton or lazy-loaded config

  • Thread safety is essential

  • You want cleaner code than double-checked locking

❌ Don’t use if:

  • Your object needs to be initialized early (eager loading is preferred)

  • You have complex dependency cycles that make static initialization risky


✅ Final Recommendation

If you're looking for a safe, performant, and clean way to implement lazy loading in Java — especially for singletons — use the static inner class approach. It's backed by the JVM, requires no locking or concurrency hacks, and works beautifully across all modern Java versions.


๐Ÿ“Œ TL;DR

  • Lazy loading improves performance and resource management.

  • Static inner classes defer loading until needed and are thread-safe by default.

  • Compared to other lazy initialization techniques, this is:

    • ๐Ÿ”’ Safer

    • ⚡ Faster

    • ๐Ÿงผ Cleaner


May 4, 2025

⚙️ Modern Guide to Calculating Fixed Thread Pool Size in Java ๐Ÿš€

⚙️ Modern Guide to Calculating Fixed Thread Pool Size in Java ๐Ÿš€

๐Ÿงต Thread Pools Are Cool — But Are Yours Optimally Sized?

Using a fixed thread pool in Java is common:

ExecutorService executor = Executors.newFixedThreadPool(10);

But is 10 the best number?

Using too many threads leads to context switching and memory pressure.
Using too few? You're leaving performance on the table.

Let’s level up: learn how to calculate the perfect thread pool size using some concurrency theory, practical math, and real examples.


๐Ÿง  Theorem: Amdahl’s Law (for CPU Utilization)

"The speedup of a program using multiple processors is limited by the time needed for sequential operations."

In simpler terms:

  • Not all parts of your code can be parallelized.

  • The more threads you add, the less benefit you get after a point (diminishing returns).

This ties directly into how you size thread pools.


๐Ÿ“ Universal Thread Pool Sizing Formula

๐Ÿ’ก From Java Concurrency in Practice:

Thread pool size = Number of cores * Target CPU utilization * (1 + (Wait time / Compute time))

✅ Where:

Variable Meaning
Cores Number of logical processors (hyperthreaded cores)
CPU utilization 0.0 to 1.0 (usually 0.8 for 80%)
Wait time Time task spends blocked (I/O, DB, etc.)
Compute time Time task spends using CPU

๐ŸŽฏ Real-Life Example (IO-Bound Tasks)

Imagine:

  • You’re writing a REST API.

  • Each request waits for a DB query (800 ms) and processes JSON (200 ms).

  • Your server has 8 logical cores.

  • You want 80% CPU usage.

๐Ÿ“Š Calculation:

int cores = 8;
double utilization = 0.8;
double waitTime = 800;
double computeTime = 200;

int poolSize = (int) (cores * utilization * (1 + (waitTime / computeTime)));
// 8 * 0.8 * (1 + 800/200) = 8 * 0.8 * 5 = 32

✅ Recommended thread pool size: 32 threads


๐Ÿ” CPU-Bound Tasks? Keep It Tight

If your task is pure computation:

Formula:

Optimal size = Cores + 1

Why +1? While one thread waits (GC, context switch), others can work.

Example:

int cores = Runtime.getRuntime().availableProcessors();
int optimalSize = cores + 1;

๐Ÿงช How to Measure Wait vs Compute Time

Use System.nanoTime() to measure portions of your task:

long start = System.nanoTime();
// Simulate DB/API/IO
long wait = System.nanoTime() - start;

start = System.nanoTime();
// Simulate computation
long compute = System.nanoTime() - start;

Use averages to estimate waitTime / computeTime.


๐Ÿ“ฆ Java Code: Dynamic Pool Sizing

public class DynamicThreadPoolCalculator {
    public static int calculateOptimalThreads(int cores, double utilization, long waitMs, long computeMs) {
        return (int) (cores * utilization * (1 + ((double) waitMs / computeMs)));
    }

    public static void main(String[] args) {
        int cores = Runtime.getRuntime().availableProcessors();
        int optimal = calculateOptimalThreads(cores, 0.8, 800, 200);
        System.out.println("Recommended thread pool size: " + optimal);
    }
}

๐Ÿ” Bonus Theorem: Little's Law

Used in queuing theory:
L = ฮป × W

Where:

  • L: average number of items in system

  • ฮป: average arrival rate

  • W: average time in the system

Helps estimate task arrival rate vs service time.


๐Ÿ“ˆ Visual Suggestion (for your blog)

  • Pie Chart: Wait vs Compute time

  • Bar Chart: Thread pool size with different wait/compute ratios

  • Heatmap: CPU usage across core count and thread pool sizes


✅ Summary Table

Task Type Sizing Formula
CPU-Bound Cores + 1
IO-Bound Cores * Utilization * (1 + Wait / Compute)
Adaptive Pool Use ThreadPoolExecutor with scaling logic

๐Ÿง  Pro Tips

  • Start with a small pool → monitor → tune

  • Use JVisualVM, JFR, or Micrometer to observe real-time metrics.

  • Combine with bounded queue size to avoid OOM under load.


๐Ÿ“Œ Conclusion

Instead of guessing thread pool size, apply concurrency principles, measure, and then let math guide your architecture.

Would you like this converted to a Markdown blog file or ready-to-publish HTML template?

๐Ÿงฉ Java Collections Cheat Sheet: List vs Set vs Map — And All Their Variants

Java’s Collection Framework is powerful — but choosing the right data structure can be confusing. This blog covers all major types: List, Set, Map, and their key implementations like ArrayList, HashSet, HashMap, etc. Let’s break them down.


๐Ÿ“ฆ 1. Collection Hierarchy Overview

               Collection
              /    |     \
           List   Set    Queue
                    \
                    Map (not a Collection, but part of framework)

๐Ÿ”ข List — Ordered, Duplicates Allowed

✅ Common Implementations:

Type Preserves Order Allows Duplicates Thread-Safe Random Access Best For
ArrayList ✅ Yes ✅ Yes ❌ No ✅ Fast (O(1)) Fast access, rare insert/delete
LinkedList ✅ Yes ✅ Yes ❌ No ❌ Slow (O(n)) Frequent insertions/deletions
Vector ✅ Yes ✅ Yes ✅ Yes ✅ Fast (O(1)) Thread-safe, legacy code

๐Ÿšซ Set — No Duplicates Allowed

✅ Common Implementations:

Type Preserves Order Sorted Allows Duplicates Thread-Safe Best For
HashSet ❌ No ❌ No ❌ No ❌ No Fast insert/check, unordered
LinkedHashSet ✅ Yes ❌ No ❌ No ❌ No Insertion order preserved
TreeSet ✅ Yes (sorted) ✅ Yes ❌ No ❌ No Sorted unique elements

๐Ÿ”Ž TreeSet uses a Red-Black Tree (log(n) operations).


๐Ÿ—บ️ Map — Key-Value Pairs (Keys Unique)

✅ Common Implementations:

Type Order Sorted Allows Nulls Thread-Safe Best For
HashMap ❌ No ❌ No ✅ One null key, many null values ❌ No Fast lookup by key (O(1) avg)
LinkedHashMap ✅ Insertion order ❌ No ✅ Same as HashMap ❌ No Ordered key-value pairs
TreeMap ✅ Sorted by keys ✅ Yes ❌ No null keys ❌ No Sorted map, navigation methods
Hashtable ❌ No ❌ No ❌ No null key/value ✅ Yes Legacy thread-safe map
ConcurrentHashMap ❌ No ❌ No ❌ No null key/value ✅ High performance Concurrent access

๐Ÿ’ก HashMap vs TreeMap vs LinkedHashMap

Feature HashMap TreeMap LinkedHashMap
Lookup Time O(1) average O(log n) O(1)
Key Order None Sorted (natural or comparator) Insertion order
Null Keys ✅ One allowed ❌ Not allowed ✅ One allowed
Use When Fast access Sorted keys needed Maintain order

๐Ÿง  When to Use What?

Use Case Recommended Class
Fast search by key HashMap
Preserve insertion order (Map) LinkedHashMap
Maintain sorted key-value pairs TreeMap
Unique values only HashSet
Sorted unique values TreeSet
Ordered unique values LinkedHashSet
Thread-safe Map (modern) ConcurrentHashMap
Fast element access ArrayList
Many insertions/deletions LinkedList

๐Ÿ” Thread-Safety Tips

  • Prefer ConcurrentHashMap over Hashtable.

  • For other collections, use:

    List<String> syncList = Collections.synchronizedList(new ArrayList<>());
    Set<String> syncSet = Collections.synchronizedSet(new HashSet<>());
    

⚙️ Bonus: How Growth Happens

Structure Growth Factor Notes
ArrayList 1.5x Internal array resized when full
Vector 2x Legacy; slower due to synchronization
HashMap ~2x Doubles capacity when load factor > 0.75

✅ Final Thoughts

Understanding the right collection for your use case can boost both performance and readability. Bookmark this post for quick reference and code like a pro!


Would you like this turned into a Markdown blog post, PDF, or HTML page for publishing?

April 18, 2025

๐Ÿ”„ Mastering the SAGA Pattern: Java vs React – A Deep Dive for Architects and Interview Champions

๐Ÿง  Why Do We Need the SAGA Pattern?

In modern distributed systems, especially microservices and rich client-side apps, the traditional database transaction (ACID) model doesn't hold up. Here's why we need the SAGA pattern:

  • ๐Ÿ”„ Ensures eventual consistency across services

  • ❌ Handles partial failure gracefully

  • ๐Ÿค Enables complex, multi-step workflows

  • ⛔ Avoids complexity and tight-coupling of 2-phase commits (2PC)


๐Ÿ“˜ What Is the SAGA Pattern?

A SAGA is a sequence of local transactions. Each service updates its data and publishes an event. If a step fails, compensating transactions are triggered to undo the impact of prior actions.

✌️ Two Main Styles:

Pattern Description
Orchestration Centralized controller manages the saga
Choreography Services communicate via events

๐Ÿ’ป SAGA in Java (Spring Boot)

๐Ÿ›️ E-Commerce Checkout Flow

  1. Create Order

  2. Reserve Inventory

  3. Charge Payment

  4. Initiate Shipping

❌ If Payment Fails:

  • Refund

  • Release Inventory

  • Cancel Order

✨ Java Orchestration Example

public class OrderSagaOrchestrator {
  public void startSaga(OrderEvent event) {
    try {
      inventoryService.reserveItem(event.getProductId());
      paymentService.charge(event.getUserId(), event.getAmount());
      shippingService.shipOrder(event.getOrderId());
    } catch (Exception e) {
      rollbackSaga(event);
    }
  }

  public void rollbackSaga(OrderEvent event) {
    shippingService.cancelShipment(event.getOrderId());
    paymentService.refund(event.getUserId(), event.getAmount());
    inventoryService.releaseItem(event.getProductId());
    orderService.cancelOrder(event.getOrderId());
  }
}

๐Ÿ“ˆ Tools & Frameworks:

  • Spring Boot

  • Kafka/RabbitMQ

  • Axon Framework / Eventuate


⚛️ SAGA in React (redux-saga)

๐Ÿšช Multi-Step Login Workflow

  1. Authenticate User

  2. Fetch Profile

  3. Load Preferences

❌ If Fetch Profile Fails:

  • Logout

  • Show Error

function* loginSaga(action) {
  try {
    const token = yield call(loginAPI, action.payload);
    yield put({ type: 'LOGIN_SUCCESS', token });

    const profile = yield call(fetchProfile, token);
    yield put({ type: 'PROFILE_SUCCESS', profile });

    const prefs = yield call(fetchPreferences, token);
    yield put({ type: 'PREFERENCES_SUCCESS', prefs });

  } catch (err) {
    yield put({ type: 'LOGIN_FAILURE', error: err.message });
    yield call(logoutUser);
    yield put({ type: 'SHOW_ERROR', message: 'Login failed' });
  }
}

๐Ÿง  Key Concepts:

  • redux-saga = orchestrator

  • yield call() = async step

  • Rollback = logout/cleanup


๐ŸŒ Real-Life Use Cases

Backend:

  • Booking systems (flight + hotel)

  • Wallet fund transfers

  • eCommerce checkouts

Frontend:

  • Multi-step login/signup

  • Form wizard undo

  • Order confirmation with rollback


๐Ÿ  Architectural Deep Dive

๐Ÿ”จ Orchestration

            ┌────────────────┐
            │ Orchestrator│
            └────────────────┘
                 │
        ┌────────────────┐
        │ Order Created │
        └────────────────┘
                 ▼
       Inventory → Payment → Shipping
        ↓         ↓         ↓
   Release ← Refund ← Cancel

๐Ÿ“š What's Next?

  1. Event Sourcing

  2. CQRS (Command Query Responsibility Segregation)

  3. Outbox Pattern

  4. Retry Patterns

  5. Step Functions / State Machines


๐Ÿ›Œ Interview Questions

Question Tip
What is a SAGA pattern? Explain distributed transaction and compensation
Orchestration vs Choreography? Orchestrator vs Event-based
SAGA in React? Use redux-saga, show generator pattern
How to rollback in microservices? Compensating transaction
Why not 2PC? Not scalable, tight coupling

๐Ÿง Self-Test Questions

  1. Design a SAGA for flight + hotel combo

  2. SAGA with Kafka vs SAGA with REST

  3. Difference: retry vs compensation

  4. How to ensure idempotency in SAGA?

  5. Drawbacks of SAGA? Latency, complexity?


๐Ÿ“„ Summary: Backend vs Frontend

Feature Java (Spring) React (redux-saga)
Purpose Distributed data consistency UI flow control
Pattern Event-driven Orchestration Generator-based orchestration
Rollback Compensating transaction State rollback/logout
Communication Kafka, REST, RabbitMQ Redux actions, async calls

Ready to master distributed consistency like a pro? SAGA is your first step to engineering Olympic-level microservice systems and stateful UI flows!

April 16, 2025

๐Ÿš€ Deploying AWS Lambda with CloudFormation: Deep Dive with Reasoning, Strategy & Implementation

Infrastructure as Code (IaC) is not just a DevOps trend — it’s a necessity in modern cloud environments. AWS CloudFormation empowers teams to define, version, and deploy infrastructure consistently.

In this blog, we'll explore a full-fledged CloudFormation template designed for deploying Lambda functions, focusing on why we structure it this way, what each section does, and how it contributes to reliable, scalable infrastructure.


✅ WHY: The Motivation Behind This Template

1. Consistency Across Environments

Manual deployment = human error. This template ensures every Lambda function in QA, PreProduction, or Production is configured exactly the same, reducing bugs and drift.

2. Scalability for Teams

Multiple teams, multiple functions. Parameterization, environment mapping, and IAM policies are designed so one template can serve dozens of use cases.

3. Security-First Approach

IAM roles, security groups, and S3 access policies follow the least privilege principle, enforcing boundaries between services and reducing risk.

4. Automated, Repeatable Deployments

Once written, this template becomes part of CI/CD pipelines — no more clicking around AWS Console for deploying each version.


๐Ÿงพ WHAT: Key Components of the Template

๐Ÿ”ง Parameters

Define runtime configurations:

  • Memory, timeout, environment

  • S3 path to code

  • Whether it’s deployed in DR or not

Why: Keeps the template generic & reusable. You plug in values instead of rewriting.


๐Ÿงฉ Mappings

Mappings connect abstract inputs to actual values:

  • VPC CIDRs by environment

  • Mongo Atlas domains

  • AWS Account-specific values

Why: Allows deployment across multiple AWS accounts and regions without code change.


๐Ÿ” IAM Roles & Policies

Provides:

  • Execution Role for Lambda

  • S3 read access for code artifacts

  • Access to services like SQS, Batch, Kinesis

Why: Lambda runs with temporary credentials. These permissions define what Lambda can touch, and nothing more.


๐ŸŒ VPC & Subnets

Lambda can be placed in VPC subnets to access:

  • Databases

  • Internal services

  • VPC-only APIs

Why: Enables secure, private connectivity — essential for production-grade workloads.


๐ŸŽฏ Scheduled Invocations

Supports setting a CRON schedule for periodic executions (e.g. cleanup tasks, polling jobs).

Why: Reduces the need for additional services like CloudWatch Events or external schedulers.


๐Ÿ”ง HOW: Putting It All Together

Let’s walk through the deployment logic of the template:

1. Define Inputs via Parameters

Parameters:
  Project:
    Type: String
  Environment:
    Type: String
    AllowedValues: [QA, PreProduction, Production]
  ...

You pass these values when you deploy the stack (e.g., via AWS CLI or CD pipelines).


2. Look Up Environment-Specific Values

Mappings:
  EnvCIDRByVPC:
    QA:
      PlatformA: 10.0.0.0/16

CloudFormation uses Fn::FindInMap to fetch the right CIDR, Mongo domain, or account ID dynamically.


3. Create IAM Roles with Granular Access

Policies:
  - PolicyName: LambdaArtifactAccess
    PolicyDocument:
      Statement:
        - Effect: Allow
          Action: [s3:GetObject]
          Resource: arn:aws:s3:::bucket-name/path/to/code.zip

This ensures the Lambda function can only read its own code and interact with intended services.


4. Provision Lambda in VPC

VpcConfig:
  SubnetIds: [subnet-1, subnet-2]
  SecurityGroupIds: [sg-xxxx]

Running Lambda in a VPC helps isolate network traffic and control what it can talk to.


5. Support for Schedule

Properties:
  ScheduleExpression: rate(1 hour)

This allows you to deploy event-driven or scheduled Lambdas without extra services.


๐Ÿง  DEEP KNOWLEDGE: Under-the-Hood Design Decisions

๐Ÿ”„ Environment Agnostic via Mappings

Instead of using if/else logic, Mappings let CloudFormation resolve values at runtime with Fn::FindInMap. This is more maintainable and faster than using Conditions.


๐Ÿ” S3 Bucket Access is Explicit

Instead of granting wide access, the template crafts exact S3 ARN paths for Lambda artifacts. This follows zero trust principles.


๐Ÿ›ก IAM Role Segregation

Lambda roles are created per function — this way, access doesn't bleed over into unrelated resources.


๐Ÿงฉ Security Group Logic Uses External Service

Outbound rules are set using:

ServiceToken: arn:aws:lambda:...

This uses a Service Catalog Custom Resource, showing how advanced teams abstract and reuse security config logic across orgs.


๐Ÿงฌ Metadata Tags

Every resource is tagged with:

  • Project

  • Platform

  • Environment

  • Cost center

  • Application owner

This is crucial for FinOps, auditing, and visibility in large-scale environments.


๐Ÿงฐ Want to Go Further?

  • ๐Ÿ’ก Add CloudWatch log groups

  • ๐Ÿช Use Lambda Destinations for post-processing

  • ๐Ÿงช Integrate with SAM for local testing

  • ๐Ÿ”„ Automate deployments with CodePipeline or GitHub Actions


✍️ Final Thoughts

This CloudFormation template is more than just a deployment script — it's a framework for building scalable, secure, and repeatable serverless architectures. Designed with flexibility, observability, and compliance in mind, it helps teams move faster without sacrificing control.

Whether you're managing one Lambda or a hundred, this structure will help you stay organized and resilient as you scale.


Let me know if you want this formatted for Medium, Dev.to, or as a GitHub README with code blocks and visual diagrams!

April 15, 2025

๐„๐ฑ๐ฉ๐ž๐ซ๐ข๐ž๐ง๐œ๐ž๐ ๐‹๐ž๐ฏ๐ž๐ฅ ๐’๐ฒ๐ฌ๐ญ๐ž๐ฆ ๐ƒ๐ž๐ฌ๐ข๐ ๐ง ๐Ÿ’ก

 A practical overview of challenging real-world system designs. Each design idea includes its purpose, blockers, solutions, intuition, and a popular interview Q&A to help you prepare for high-level interviews or system architecture discussions.

Use this as a cheat sheet or learning reference to guide your system design thinking.

# System Design Problem Intuition & Design Idea Blockers & Challenges Solution/Best Practices Famous Interview Question & Answer
1 URL Shortening (bit.ly) Map long URLs to short hashes. Store metadata and handle redirection. High scale, link abuse Use Base62/UUID, Redis cache, rate-limiting Q: How to avoid collisions in shortened URLs? A: Use hash + check DB for duplicates.
2 Distributed KV Store (Redis) Store data as key-value pairs across nodes. Network partitions, consistency Gossip/Raft protocol, sharding, replication Q: How to handle Redis master failure? A: Sentinel auto-failover.
3 Scalable Social Network (Facebook) Users interact via posts, likes, comments. Need timeline/feed generation. Feed generation latency, DB bottlenecks Precompute feed (fanout), cache timeline Q: How is news feed generated? A: Fan-out to followers or pull on-demand.
4 Recommendation System (Netflix) Suggest content based on user taste + trends Cold start, real-time scoring Use hybrid filtering, vector embeddings Q: How to solve cold start? A: Use content-based filtering.
5 Distributed File System (HDFS) Break files into blocks, replicate across nodes. Metadata scaling, file recovery NameNode for metadata, block replication Q: How does HDFS ensure fault tolerance? A: 3x replication and heartbeat checks.
6 Real-time Messaging (WhatsApp) Deliver messages instantly, maintain order. Ordering, delivery failures Kafka queues, delivery receipts, retries Q: How to ensure delivery? A: ACK, retry, message status flags.
7 Web Crawler (Googlebot) Crawl web, avoid duplicate/irrelevant content. URL duplication, crawl efficiency BFS + filters, politeness policy Q: How to avoid crawling same URL? A: Normalize + deduplicate with hash.
8 Distributed Cache (Memcached) Store frequently accessed data closer to users. Cache invalidation, stampede TTL staggering, background refresh Q: How to handle cache stampede? A: Use mutex/locks for rebuilds.
9 CDN (Cloudflare) Serve static assets from edge for low latency. Cache expiry, geolocation Use geo-DNS, cache invalidation APIs Q: How does CDN reduce latency? A: Edge nodes cache closer to user.
10 Search Engine (Google) Index content and rank pages on queries. Real-time indexing, ranking MapReduce, inverted index, TF-IDF Q: How does Google rank pages? A: Relevance + PageRank + freshness.
11 Ride-sharing (Uber) Match drivers to riders using location data. Geo-search, dynamic pricing Use GeoHashing, Kafka, ETA predictions Q: How does Uber find nearby drivers? A: Geo index or R-tree based lookup.
12 Video Streaming (YouTube) Store and stream videos with low buffer. Encoding, adaptive playback ABR (adaptive bitrate), chunking, CDN Q: How to support multiple devices? A: Transcode to multiple formats.
13 Food Delivery (Zomato) Show restaurants, manage orders, track delivery. ETA accuracy, busy hours ML models for ETA, real-time maps Q: How is ETA calculated? A: Based on past data + live traffic.
14 Collaborative Docs (Google Docs) Enable multiple users to edit in real time. Conflict resolution Use CRDTs/OT, state sync Q: How does real-time collaboration work? A: Merge edits using CRDT.
15 E-Commerce (Amazon) Sell products, track inventory, handle payments. Concurrency, pricing errors Use event sourcing, locking, audit trail Q: How to handle flash sale? A: Queue requests + inventory locking.
16 Marketplace Recommendation Personalize based on shopping history. New users, noisy data Use embeddings, clustering, trending items Q: How to personalize for new user? A: Use trending/best-selling items.
17 Fault-tolerant DB Ensure consistency + uptime in failures. Partitioning, network split Raft/Paxos, quorum reads/writes Q: CAP theorem real example? A: CP (MongoDB), AP (Cassandra).
18 Event System (Twitter) Send tweets/events to followers in real time. Fan-out, latency Kafka, event store, async processing Q: Push or pull tweets? A: Push for active, pull for passive.
19 Photo Sharing (Instagram) Users upload, view, and like photos. Storage, metadata Store media on CDN/S3, DB for metadata Q: Where are images stored? A: CDN edge, S3 origin.
20 Task Scheduler Schedule and trigger jobs reliably. Time zone issues, duplication Use cron w/ distributed locks Q: How to ensure task runs once? A: Use leader election or DB locks.

๐Ÿง  Tips for Developers:

  • Always consider scalability (horizontal vs vertical).

  • Trade-offs are key: CAP, latency vs availability.

  • Use queues to decouple services.

  • Think about observability: logging, metrics, alerts.

๐Ÿ“š Want to go deeper? Check out:

  • "Designing Data-Intensive Applications" by Martin Kleppmann

  • SystemDesignPrimer (GitHub)

  • Grokking the System Design Interview (Educative.io)

Let me know if you'd like deep dives, diagrams, or downloadable PDF/Markdown version!

Fresher Level System Design Blog

Introduction

This blog is a quick reference guide for freshers preparing for system design interviews. Each topic below is summarized in 3-4 lines and presented in a table format for easy review. It also includes common interview questions, challenges, and suggestions to help you build intuition.

# System Design Topic Design Summary Challenges / Blockers Suggested Solution Famous Interview Question & Answer Intuition & Design Ideas
1 URL Shortening Service Use a key-value store to map short codes to long URLs. Generate short codes using Base62. Cache frequently accessed URLs. Collision in short code generation Use hashing + collision checks or UUID/base62 encoding. Q: How do you avoid collisions in short URL generation? A: Use base62 encoding of incremental IDs or UUID + retry on collision. Think of it like a dictionary: you store a short code and retrieve the original. Add expiration support and track analytics.
2 Basic Chat Application Use WebSockets for real-time messaging. Store messages in a NoSQL DB. Ensure message ordering and delivery. Ensuring delivery and message order Use message queues and timestamps, ACKs from client. Q: How would you ensure message order in group chats? A: Use timestamps with logical clocks or message queues per chat room. Use WebSocket for real-time, and fallback to polling for older clients. Consider how to handle offline messages.
3 File Storage System Use object storage like S3 for files. Store metadata in a DB. Provide upload/download APIs. Large file handling, partial uploads Use chunked upload/download and resumable uploads. Q: How would you implement versioning for files? A: Store file version history with timestamps in metadata DB. Think Dropbox: sync files across devices with deduplication and conflict resolution.
4 Social Media Platform Use relational DB for users/posts. Cache timelines. Implement followers and feed service. High write/read traffic on feeds Use fan-out on write/read strategy and timeline caching. Q: How do you design the user timeline? A: Use fan-out on write for small followers, fan-out on read for celebrities. Prioritize read-heavy optimization. Add notification and media support.
5 Simple Search Engine Crawl pages and index using inverted index. Use ranking algorithm for results. Keeping index up to date Use distributed crawlers and scheduled re-indexing. Q: How would you rank search results? A: Use TF-IDF, PageRank, or user behavior signals like clicks. Think Google-lite: crawl, index, rank. Add caching and autosuggestions.
6 E-commerce Website Use microservices: product, cart, order, payment. SQL DB for product and inventory. Inventory sync and order consistency Use distributed transactions or eventual consistency with event queues. Q: How would you handle high traffic flash sales? A: Use inventory preloading to Redis and lock stock before checkout. Start with catalog, then cart/order/payments. Consider promotions, reviews, delivery tracking.
7 Ride-Sharing System Match riders and drivers using location. Real-time tracking. Accurate location matching, dynamic pricing Use geo-hashing, real-time map APIs, and ML for pricing. Q: How do you match drivers and riders efficiently? A: Use a spatial index like QuadTrees or GeoHash. Focus on live map, ETA, and surge pricing. Add cancellation/reassignment logic.
8 Video Streaming Service Use CDN for delivery. Store videos in chunks. Use adaptive bitrate for smooth playback. Latency and buffering Use HLS/DASH protocol and edge caching. Q: How to stream to users with different network speeds? A: Use adaptive bitrate streaming with multiple resolutions. Break videos into chunks. Use a manifest file (HLS). Add user history, playlist, and DRM.
9 Recommendation System Use collaborative or content-based filtering. Precompute recommendations. Cold start for new users or items Use hybrid approach with default/popular items. Q: How would you recommend items to a new user? A: Show trending items or use demographic similarity. Think YouTube/Netflix. Store events (views, clicks), then use ML models offline for suggestions.
10 Food Delivery App Use microservices: restaurant, user, order, delivery. Real-time tracking. Live order tracking, delivery partner availability Use Google Maps APIs + ETA algorithms and dynamic delivery assignment. Q: How do you ensure food is delivered fresh and on time? A: Assign nearest delivery agent, optimize route, notify delays. Focus on real-time updates and restaurant status. Add rating system for feedback.
11 Parking Lot System Track available slots in DB. Assign spots. Entry/exit logs and payments. Real-time availability accuracy Use sensors or manual sync + DB updates. Q: How would you design for multiple floors or zones? A: Partition lot into zones and track slots per zone in DB. Add reservation system, payments, QR/barcode entry. Consider IoT for sensors.
12 Music Streaming Service Store music on cloud. Use playlists, search, recommendations. Latency and copyright handling Use CDN + streaming DRM integration. Q: How would you support offline playback? A: Encrypt songs on device with limited-time license key. Similar to video streaming but lighter files. Add social sharing, lyrics, etc.
13 Ticket Booking System Locking to avoid double bookings. Store event/show data in DB. High concurrency for popular events Use row-level locking or optimistic locking strategies. Q: How to prevent double booking of the same seat? A: Use atomic seat lock with expiry during checkout. Add seat map UI, payment integration, reminders. Handle refunds/cancellations.
14 Note-Taking Application CRUD operations. Sync across devices. Store in cloud DB. Conflict resolution in sync Use timestamps + conflict resolution policies. Q: How to sync notes across multiple devices? A: Use timestamps and push updates via WebSocket or polling. Think Notion/Keep. Add tags, reminders, and collaborative editing.
15 Weather Forecasting System Collect weather data from APIs/sensors. Store time-series data. High frequency updates, regional accuracy Use time-series DBs and ML-based predictions. Q: How do you predict weather for a new location? A: Use nearby station data and interpolate using models. Combine IoT sensors, external APIs, and ML models. Add alerting and maps.
16 Email Service Use SMTP to send emails. Store in DB. Support inbox, outbox, spam. Spam filtering and delivery issues Use heuristics + feedback systems + email queue management. Q: How would you ensure email delivery reliability? A: Use retries, bounce monitoring, and SPF/DKIM setup. Design mailbox, filters, attachments. Add UI like Gmail.
17 File Sync System Use file hash and timestamps. Sync diffs. Handle conflict resolution. Merge conflicts Use last-write-wins or manual merge strategy. Q: How do you sync two files modified at the same time? A: Detect conflict and ask user to merge manually. Think Dropbox/GDrive. Compress, diff-check, and background upload.
18 Calendar Application Support events, reminders, recurrence. Notifications and sync. Time zone handling, reminders Normalize time and use push notification service. Q: How to handle daylight saving and multiple time zones? A: Store in UTC and convert to local for display. Focus on recurrence (RRULE), invites, rescheduling. Add integrations like email or Google Meet.
19 Online Quiz Platform Create quizzes. Store answers, scores. Track user progress. Prevent cheating, real-time scoring Use proctoring APIs or time-restricted tests with session tracking. Q: How to handle large-scale exam with many users? A: Use horizontal scaling and rate limit cheating behavior. Think Google Forms + timer. Add leaderboard, difficulty levels.
20 Auth System Use OAuth2 or JWT. Store hashed passwords. Support MFA. Token expiration, brute force attacks Use refresh tokens, rate limiting, and password encryption (bcrypt). Q: How do you revoke JWT tokens? A: Use token blacklist or short expiry + refresh token. Start with sign-up/login, session vs token, role-based access. Add social login and 2FA.

Conclusion

This concise table helps you quickly review common system designs. Build a few for hands-on experience and better understanding.

Learn More: