torsdag 6 mars 2025

DDD dead man walking


Domain-Driven Design (DDD)  was a popular approach for designing complex software systems around 15-20 years ago, especially when building monoliths or web services. However, there are super valid arguments against using DDD, specially you work with microservice architecture and particularly when working with Spring Boot. Here are some points to consider:

1. Overhead and Complexity

   Argument: DDD introduces additional layers of abstraction that can increase the complexity of your microservice.

Impact: For microservices, this overhead is not justified. Spring Boot is often used to build lightweight, fast-to-develop services, and DDD can slow down development by requiring rigorous modeling and design upfront. Useless work, because in a microservice the important think is the spefic business domain the microservice has to own and the different contracts it has upstream against consumers of REST API but also other downstream consumers if your service needs to implement event sourcing or your microservice has to be an important component in your company's message driven architecture.

A simpler CRUD-based approach might suffice for straightforward microservices, reducing development time and cognitive load. For more central microservice you maybe implement Event Sourcing.

2. Learning Curve

Argument: DDD requires a deep understanding of its concepts and how to implement them effectively and it is knowledge about how to design, with right semantics etc. not to code.

Impact: Teams unfamiliar with DDD may struggle to apply it correctly, leading to poorly designed systems or wasted time. Spring Boot developers might prefer more straightforward patterns that align with their existing knowlegde

3. Misalignment with Microservice Granularity

Argument: DDD emphasizes bounded contexts, which might not always align with the granularity of microservices.

Impact: The use of DDD can lead to microservices that are too fine-grained, increasing operational complexity without providing significant business value.

Focus on business capabilities rather than strict DDD boundaries when defining microservices.

4. Over-Engineering

Argument: DDD encourages rich domain models, which can lead to over-engineering.

Impact: Not all microservices require complex domain logic. For example, a service that primarily handles data storage or integration with third-party APIs might not benefit from a full DDD approach.

5. Performance Considerations

Argument: DDD's emphasis on aggregates and consistency boundaries can lead to inefficient data access patterns.

Impact: In a microservices architecture, fetching large aggregates or enforcing transactional consistency across services can hurt performance. Spring Boot's simplicity and focus on lightweight services might clash with DDD's heavier design.

6. Tooling and Frameworks

Argument: Spring Boot provides excellent support for building RESTful services and integrating with databases, but it doesn't enforce or align with DDD principles.

Impact: Developers might need to write additional boilerplate code or use third-party libraries to implement DDD patterns, which can slow down development.

Leverage Spring Boot's strengths without forcing DDD where  it doesn't fit.

7. Iterative Development

Argument: DDD requires a deep understanding of the domain upfront, which can be challenging in agile environments where requirements evolve frequently.

Impact: In fast-paced projects, the time spent on domain modeling might delay delivery. Spring Boot's rapid development capabilities might be better suited to iterative, feedback-driven approaches.

8. Not All Domains Are Complex
 
Argument: DDD is most valuable in domains with complex business rules and logic.

Impact: For domains that are primarily data-driven or lack complex rules, DDD adds unnecessary complexity. Spring Boot's simplicity shines in these scenarios.

9. Distributed Systems Challenges
Argument: DDD doesn't inherently address the challenges of distributed systems, such as eventual consistency, service discovery, or fault tolerance.

Impact: In a microservices architecture, these concerns are critical, and DDD alone won't solve them. Spring Boot's ecosystem (e.g., Spring Cloud) provides tools to handle these challenges, but they might not align neatly with DDD.

10. Team Dynamics

Argument: DDD requires close collaboration between developers and domain experts.
 
Impact: If the team lacks access to domain experts or struggles with communication, DDD might not deliver its intended benefits. Spring Boot and microservice architecture allows teams to work more independently.

Conclusion
DDD was maybe a powerful tool for designing web services or complex monoliths, but it is totally unnecessary with microservices and Spring Boot. 


lördag 25 januari 2025

What is a REST API?

People mistakenly believe they are designing REST API:s but actually they design RPC API:s. 
The misconception has its root in the lack of theoretical knowledge about REST API and the RESTFul Principles. 
I don’t trust people that have a very rigid view about how a REST API should be implemented, claiming that their way to design is best practices on the Internet. 
The truth is that the majority of developers don’t know the basic principles of REST API. Majority of Microservices out there are RPC API:s not REST API:s. And that was a frustration Roy Fielding (the father of REST) already expressed in 2008.
 
There are few similarities:
  • Both use HTTP
  • Client-Server Model
 
There are crucial distinctions:

  • Resource-Oriented vs. Action-Oriented:
    • REST: Focuses on manipulating resources (e.g., "users", "products") through HTTP verbs (GET, POST, PUT, PATCH, DELETE) and respecting the semantics of the verbs and the characteristics, like the idempotency of some verbs.
    • RPC: Primarily focuses on executing remote procedures or functions (e.g., "getUserById", "createProduct").
  • Data Format:
    • REST: Often leverages standardized data formats like JSON or XML.
    • RPC: Can use various data formats, including custom ones.
  • Semantics of the URL:
    • REST: URLs typically represent resources (e.g., /users/123, /products).
    • RPC: URLs might reflect function names (e.g., /getUser, /createProduct).
  •  Flexibility:
    • REST: Generally more flexible and easier to evolve due to its focus on resources and standard HTTP verbs.
    • RPC: Can be more tightly coupled to specific implementations.
While both can use HTTP and operate within a client-server model, REST emphasizes a resource-oriented approach with standardized HTTP verbs, while RPC focuses on remote procedure calls, often with less emphasis on resource representation and the creation of semantic correctness.
Roy Fielding, the creator of REST, expressed significant frustration with how the term "REST API" is commonly misused. Here's a breakdown of his key concerns:
 
Misinterpretation of Core Principles:

  • Focus on HTTP: Many developers perceive REST solely as using HTTP, overlooking its architectural constraints and guiding principles. Fielding emphasizes that REST is not just about using HTTP verbs (GET, POST, PUT, PATCH, DELETE) but about adhering to a specific architectural style, understanding and implementing the semantics of the verbs within constraints like statelessness, cacheability, and uniform interface. Despite some API:s have idempotency as a requirement, they don’t use verbs that warrant idempotency and respect the semantics of the endpoints.
  • Ignoring HATEOAS: A core principle of REST is "Hypermedia as the Engine of Application State" (HATEOAS). This means that the API should provide links within its responses, allowing clients to discover and navigate resources dynamically. Many so-called "REST APIs" lack this crucial aspect, relying on pre-defined client-side logic.
  • Oversimplification and Misuse: "REST" as a Buzzword: The term "REST API" has become a buzzword, often used indiscriminately for any HTTP-based API, regardless of its actual adherence to REST principles. This dilutes the meaning and makes it difficult to distinguish truly RESTful APIs from others.
  • Focus on CRUD Operations: Many APIs labeled as "RESTful" primarily focus on CRUD operations (Create, Read, Update, Delete) on resources, neglecting the broader architectural considerations of REST. REST API don’t need to be CRUD API:s, an API can be Decision Making API or other implementation style dictated by the requirements, the important thing is the broader architectural considerations and semantics.

Impact on API Design and Evolution:

  • Limited Flexibility: Misinterpreting REST can lead to API designs that are less flexible and more tightly coupled to specific client implementations.
  • Hindered Innovation: By not adhering to true REST principles, developers miss out on the potential benefits of a more flexible and evolvable architecture.
Fielding laments that the term "REST API" has been widely misused and misunderstood, leading to suboptimal API designs and hindering the realization of the full potential of RESTful architectures. He emphasizes that true REST is more than just using HTTP; it's about adhering to a specific set of architectural constraints that promote flexibility, scalability, and evolvability.

Many developers misuse HTTP verbs, leading to inconsistent and unpredictable APIs. 

  • Common Misuses:
    •  Overusing POST: Many developers use POST for updates (instead of PUT or PATCH), even when the operation is idempotent. This violates the intended semantics of POST, which is typically for creating new resources, if the idempotency requirement is not included on creation.
    • For Idempotent Operations: Using POST for operations that should be idempotent (like updating a specific resource) can lead to unexpected side effects if the request is repeated.
    • Ignoring PUT vs. PATCH: Using POST for Partial Updates: Many use POST for partial updates (updating only specific fields of a resource), while PATCH is the correct verb for this purpose.
  • Misinterpreting Idempotency:
    • Confusing with Safety: Some developers mistakenly believe that all idempotent operations are safe (have no side effects). While all safe methods are idempotent, the reverse is not true. PUT and DELETE are idempotent but not safe.
    •  Consequences: Inconsistent APIs: Misusing verbs makes APIs harder to understand and use, leading to confusion and errors.
    • Unexpected Behavior: Incorrect verb usage can result in unexpected side effects, such as unintended data modifications or multiple creations of the same resource.
    • Limited Caching: Improper use of verbs can hinder caching mechanisms, as caches may not be able to effectively store and reuse responses.
    • Reduced Interoperability: APIs that don't adhere to HTTP verb semantics are less interoperable with other systems and tools that rely on these standards.
Best Practices? 
  • Use Verbs Correctly:
    • GET: Retrieve a resource.
    • POST: Create a new resource. (If and only if idempotency is not required)
    • PUT: Replace an entire resource. (also for creation if idempotency is required)
    • PATCH: Update specific parts of a resource.
    • DELETE: Remove a resource.
  • Understand Idempotency: Be aware of which verbs are idempotent and design your API accordingly,
  • Follow HTTP Standards: Adhere to the HTTP specification and best practices for verb usage.
By adhering to these principles, developers can create more robust, predictable, and maintainable API:s that are easier to use and integrate with other systems.
While POST is generally used for creating resources, there are situations where you need idempotency in a creation scenario. Here's how you can achieve that with PUT:

Idempotency

  • Concept: Introduce a unique identifier (like a UUID) within the request body if you rely on calling clients or implement a server-side identification for requests.
  • Implementation: 
    •  The server checks for this identifier.
    • If the identifier is encountered for the first time, the resource is created, and the identifier is associated with it.
    • If the identifier is already present, returns the existing resource (if the creation was successful in the past).
While POST is not inherently idempotent therefore have to be used ONLY when idempotency is not required, you have to use PUT when idempotency is required. PUT is idempotent according to HTTP Specification and it helps you to design a semantically right and more RESTFul API.
At the end Richmond Maturity Model explain very well what we are talking about: