Giter VIP home page Giter VIP logo

jmolecules's People

Contributors

beatngu13 avatar denniseffing avatar haisi avatar hschwentner avatar mahatmafatalerror avatar murdos avatar odrotbohm avatar sascha4msx avatar sebsprenger avatar sesamzoo avatar stephanpirnbaum avatar wimdetroyer avatar zambrovski avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jmolecules's Issues

Entity-Annotation should reference owning Aggregate

The interface org.jmolecules.ddd.types.Entity has generics to specify the aggregate root the entity belongs to. However, for the annotation, this is currently not the case. To have this consistent I propose to add an optional parameter to the @Entity annotation to specify the aggregate root. This would allow tools such as ArchUnit or jQAssistant to validate access to entities.

Opinions?

Should we have base types to avoid boilerplate code?

The DDDBITS provide two kinds of things:

  1. Architectural annotations -> These have been superseded by jMolecules now
  2. Base types with infrastructure to avoid boilerplate code
  • Should we move 2. also to jMolecules?
  • If yes: would that be a part of jmolecules-ddd or a new library to keep jmolecules-ddd as an “implementation free” lib?

From the DDDBITS documentation:

Entities

From the Blue Book we know that entities must have an identity.
Typically we want that equals() and hashcode() are based on this identity.
The base class Entity<ID> provides implementations for this.

Example:

import io.hschwentner.dddbits.annotation.*;
import io.hschwentner.dddbits.basetype.*;

@Entity
public class BankAccount extends Entity<IBAN> {

    public BankAccount(IBAN iban) {
        super(iban);
    }

}

Value Objects

Since we don't have value types in Java yet, we have to simulate values with objects.
(That may change with the advent of Project Valhalla.)
For the time being, this means unfortunately that we have to write a lot of boilerplate code for a well-implemented value object.
DDDBITS provide so called tiny types that help to reduce that boilerplate code for simple value types.

Example:

import io.hschwentner.dddbits.annotation.*;
import io.hschwentner.dddbits.basetype.*;

@ValueObject
public class IBAN extends TinyType<String> {

    private IBAN(String ibanString) {
        super(ibanString);
    }

    public IBAN of(String ibanString) {
        return new IBAN(ibanString);
    }

}

Value Objects are identityless and immutable.

Immutability in Java comes with only final fields plus methods that never mutate the state.
(That means we only have commands in the sense of command-query-separation[3].)

No identity in Java is reached by overwriting equals() with an implementation that is based on the values of the fields.
Such an implementation and similar implementations for hashcode() and toString() are provide by the TinyType<V> super class.


Something similar could be done with Lombok, but many projects do not want to couple their domain layer to a technical library.

Add Spring plugin

Similar to the JPA plugin (see #8) we could translate jDDD annotations into their Spring equivalents.

Define strategy to avoid need for over declaring architectural concepts

jDDD artifacts are designed to be usable as independently as possible. E.g. the onion architecture annotations are usable completely without the building blocks annotations in jDDD Core. That however also imposes an interesting challenge. Let's say your project combines the two artifacts. To benefit from both the declarations, you would now have to do the following:

@AggregateRoot // from jddd-core
@DomainLayer // from jddd-architecture-onion
class MyAggregate { … }

This is basically expressing the same thing twice as you could argue that from the fact, that MyAggregate is an @AggregateRoot, it belonging to the domain layer is implicit.

A very direct solution for that would be to meta-annotate @AggregateRoot with @DomainLayer. However, that would introduce a dependency in the wrong direction and kind of imply that jDDD Core annotations would imply onion architecture, despite that technical dependency not be a strong one at runtime (as annotations can be missing without failure). It would be logically more consistent to transparently "annotate" MyAggregate with @DomainLayer if it is annotated with @AggregateRoot and jDDD Onion Architecture is in use.

There are two options to achieve that:

  1. We could leave that semantic derivation to downstream tools that can embed such rules into the implementation of their analysis. E.g. jQAssistant could easily add that additional metadata to its model based on that rule. I'd love to see that in those tools (ArchUnit, too) but at the same time it means that other tools evaluating the annotations only would not see those "derived" annotations.
  2. Just like we already prototypically add technology specific annotations derived from metamodel ones in the jDDD JPA Plugin, we could use ByteBuddy to declares these additional annotations transparently by implementing a plugin.
  3. Lombok seems to be getting a meta-annotation feature soon.

Extended generics for Identifier interface

Summary

Does it make sense to enrich the Identifier interface with generic parameters so that the model implementation can be inspected for valid relationships more easily and does the effect of that move outweigh the cost (breaking change, a slight bit more verbosity / boilerplate)?

Context

Identifier is currently a marker interface that doesn't use any generics to establish a relationship to an Identifiable. This causes ambiguities when inspecting a type using multiple Identifier implementations:

class Order {
  OrderIdentifier id;
  CustomerIdentifier customerId;
}

While a human can probably guess that id contains the identifier of Order (due to the field name and type name pattern), without further assumptions there's no way for tooling to differentiate between the identifier of the owning type and an identifier that refers to some other identifiable

Current ways to deal with this situation

We already have Association that allows to explicitly declare relationships to other Aggregate instances. One can argue that instead of using an Identifier as field type directly, one should rather use Association to express the relationship explicitly. That said, there are a couple of constraints this imposes which it would be nice to get input for whether they're a good thing because they're guiding developers to do the right thing or rather perceived as invasive:

  • Relationships can only point towards an AggregateRoot. While that can be considered appropriate as we must not point towards an entity contained in another aggregate root. That said, the relationships to entities contained in the owning aggregate root always have to be modeled as entity instances. Mapping only the identifiers results in the problem mentioned above. Does it actually make sense to only map the identifier of a contained entity in the first place? If so, how would you materialize it? Are there modeling cases in which using an ID is just sufficient, and you wouldn't necessarily need to materialize it?
  • Mapping an Association to a persistence model can be a bit tedious. Currently, integration into JPA exists in jMolecules Integrations, which works around some JPA limitations by a bit of code generation. It's obvious that you could just argue that this is not an argument, as a separate persistence model is preferred anyway.

Potential solution

If we come to the conclusion that we would like to support multiple Identifier implementations as field types in a model class, one way to tighten the model would be to introduce generic parameters to Identifier. This would need quite a few changes to existing generic type arrangement that would clearly break existing applications. Here's what the move would look like:

Before After Description
Identifiable<ID> Identifiable<T extends Identifiable<T, ID>, ID extends Identifier<T, ID>> New generic parameter
Identifier Identifier<T extends Identifiable<T, ID>, ID extends Identifier<T, ID>> Two new generic parameters, previously none
Entity<T extends AggregateRoot<T, ?>, ID> extends Identifiable<ID> Entity<T extends AggregateRoot<T, ?>, S extends Entity<T, S, ID>, ID extends Identifier<S, ID>> extends Identifiable<S, ID> Three generic parameters instead of two -> breaking
AggregateRoot<T extends AggregateRoot<T, ID>, ID extends Identifier> extends Entity<T, ID> AggregateRoot<T extends AggregateRoot<T, ID>, ID extends Identifier<T, ID>> extends Entity<T, T, ID> Identifier tightened, breaks compilation for unadapted Identifier implementations
Association<T extends AggregateRoot<T, ID>, ID extends Identifier> extends Identifiable<ID> Association<T extends AggregateRoot<T, ID>, ID extends Identifier<T, ID>> extends Identifiable<T, ID> Identifier tightened, breaks compilation for unadapted Identifier implementations
Repository<T extends AggregateRoot<T, ID>, ID extends Identifier> Repository<T extends AggregateRoot<T, ID>, ID extends Identifier<T, ID>> Needs adaption of Identifier

Examples of necessary changes from the Spring RESTBucks example:

Before After
OrderIdentifier implements Identifier OrderIdentifier implements Identifier<Order, OrderIdentifier>
LineItem implements Entity<Order, LineItemIdentifier> LineItem implements Entity<Order, LineItem, LineItemIdentifier>
PaymentIdentifier implements Identifier PaymentIdentifier<T extends AggregateRoot<T, PaymentIdentifier<T>>> implements Identifier<T, PaymentIdentifier<T>>

Here are the major effects of that move:

  • We now need Identifier implementations per Identifiable. Previously, it was possible to share Identifier implementations. Adding the generics primarily affect type hierarchies (like Payment in the example above).
  • There's a degree of boilerplate introduced as both Identifier and Entity now need to be self-referencing. Entity would end up with three generic parameters, which can understandably perceived as too noisy.
  • Identifiable's getId() method now returns a parameter that is bound to a generic type parameter containing a bound. The code generation integration for Spring Data's Persistable that previously was able to use the induced getId() method from the domain type is now not properly bound to that method anymore. The test cases contained in the adapted jMolecules Integrations prototype branch fail to invoke the correct method. I assume, there's some bridge method missing being created during code generation. I'd investigate this further if we decided to pursue this in the first place.

WIP Prototype

There are branches that explore the feasibility of this:

Refine artifact structure

  • …-ddd
  • …-events
  • …-cqrs
  • …-architecture
    • …-architecture-layered
    • …-architecture-onion
    • …-hexagonal
    • …-clean
  • …-integration
    • …-archunit
    • …-jpa
    • …-spring
  • …-examples

What should a strict layered architecture look like?

I can't see any example projects to compare my own against, while trying to migrate over.

Although I can kinda guess what it should look like, I want to double check that I'm not making it too complex in hierarchy, as the project I'm using isn't very complex

Should we introduce specific annotations for Event Sourcing?

It needs to be further discussed if we should add annotations specific for event sourcing, i.e.

  • the event itself
  • the handler and publisher of that event

This is continuing the discussion of PR #39

The addition of sourcing events would allow external tools (such as jQAssistant) to easily identify what are:

  • actual domain events that trigger a functionality in the same or another application
  • events used to enable the technical aspect of event sourcing

As mentioned in the PR, domain events have a domain specific context and thus may only model part of the data. Event sourcing events, on the other hand, do not limit the level of detail (e.g. credit card details would not be masked) and only contain changed data. Actual domain events may contain more information.

Also have a look into this article: https://www.innoq.com/en/blog/domain-events-versus-event-sourcing/

Provide a way to specify a reference to identity using annotation

Short

Introduce a new stereotype IdentityRef expressing a reference to a Identity as annotation.

Description

I stumbled upon an interesting question implementing command dispatching in CQRS. The command model accessed via aggregate root needs to be able to build an identifier from the context of a command to target the correct aggregate / entity.

A very easy way to target is to specify the target identifier inside the command. Firstly, I thought I could use Identifier or @Identity from jmolecules-ddd for this purpose, but it seems to be very strange... The command itself is an immutable value object and putting a field inside of it marked with @Identity seems to be confusing... A better approach is to use a different stereotype IdentityRef (as a annotation) to express the "pointer-to-identity" semantics.

Look on the follow example:

@Command(namespace = "customer", name = "UpdateCustomerProfile")
data class UpdateCustomerProfileCommand(
  @IdentityRef
  val customerId: CustomerId,
  val firstName: FirstName,
  val lastName: LastName
)

@AggregateRoot
class CustomerProfile {

  @Identity
  lateinit var customerId: CustomerId

  @CommandHandler(namespace = "customer", name = "UpdateCustomerProfile")
  fun handle(command: UpdateCustomerProfileCommand) {
    // ...  
  }
}

Is the Association marker interface is exactly designed for this? Then I think the definition of the association with an annotation should be possible:

/**
 * Marks the reference to identity.
 * Carries optional the identity type and the identifiable type.
 */
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Documented
public @interface IdentityRef {

    /**
     * Defines identity type.
     *
     * @return class defining the identity type.
     */
    Class<?> identityType() default void.class;

    /**
     * Defines the aggregate type.
     *
     * @return class defining the identifiable type (entity or aggregate).
     */
    Class<?> identifiableType() default void.class;
}

Introduce annotations and types for CQRS / Event Sourcing

I just spoke to @abuijze of Axon Framework and we wondered whether it'd make sense to introduce annotations and types to declare CQRS / Event Sourcing building blocks:

  • @Command – type annotation
  • @CommandHandler – method annotation
  • @(Domain)EventHandler – method annotation
  • @ViewModel / @Projection – type annotation

Axon also provides annotations for querying:

  • @Query
  • @QueryHandler

but they seem to be a little more specific to Axon rather than a CQRS / ES concept that is to be mapped to types and packages in general.

Open questions

  1. Should this be a dedicated artifact (jddd-cqrs) or a part of the already existing jddd-architecture artifact. As using CQRS / ES as implementation is a pretty significant decision, I personally tend to vote for the former as I wouldn't want to impose the types on the classpath of someone who just pulled in the jddd-architecture artifact on the classpath to e.g. demarcate layers.
  2. Axon currently provides @EventHandler but we have chosen @DomainEvent in the jddd-events module. Thus, I'd vote to name the corresponding handler annotation @DomainEventHandler for consistency.
  3. @ViewModel or @Projection? I tend to vote for the former.

Additional metadata for Hexagonal Architecture's `@Port`s and `@Adapter`s

For documentation purposes, it would be nice to be able to declare a port or adapter's logical name and description in the annotation. This could be used to place human-readable flavors of their domain semantics right with the code that could be extracted into developer documentation.

  • name() – defaults to the package or type name.
  • description() – defaults to the Javadoc of either the package or type

This especially becomes interesting if there's not a 1:1 mapping between, for example, port and type. Using the same port names would allow them to be grouped and displayed in docs. Assume some API / SPI split of some application feature that could use different packages to place the corresponding types in them but define a single place (the @(Primary|Secondary)Port annotation on the package-info.java) to define a human-readable description of each of them.

Follow-up of #71.

Enable annotations to be used as meta-annotations

As discussed in the PR #39 , annotations should be usable as meta-annotations.

This should be added for:

  • jmolecules-architecture-cqrs
  • jmolecules-ddd (except BoundedContext?)
  • jmolecules-events

Does it make sense to add it to the layer and ring architecture? I don't think so, but let's discuss it.

Add kMolecules DDD flavor of jMolecules DDD to work around issues in Kotlin

jMolecules DDD types are helping a lot but there are some annoying limitations due to Kotlin's Java interoperability.

The main limitation is due to Identifiable#getId method that conflicts with constructor's id field as shown below:

//Won't work as Kotlin's generated getter has the same signature as Identifiable#getId method
class Conflict(val id: Id, val other: String): Entity<Portal, Id> {
    override fun getId(): Id = id
}
// Won't work as id 'overrides nothing'
class Override(override val id: Id, val other: String): Entity<Aggregate, Id>

Obviously it is possible to rename constructor's id field but it makes framework integration brittle since projects such as the excellent Spring Data instantiates objects via constructor if I'm not mistaken. It also hurts Kotlin's conciseness and integrate poorly with Kotlin's data classes.

To cope with those issues I created Kotlin counterparts for jMolecules DDD types. I would be happy to contribute a PR if you think it makes sense

Should we introduce @Newable / @Injectable?

In their implementations, DDD building blocks have a well defined mapping towards who is managing the lifecycle of them. Two concepts can be found:

  • Newables – concepts manually instantiated in domain code either via constructors or factory methods. Building blocks that fall into that category: value objects, entities, aggregates.
  • Injectables – concepts instantiated and assembled in a canonical place (either by hand crafted code or some kind of container managing the object lifecycle). Those are usually wired into through the concept of dependency injection (hence the name). Building blocks to mention here: factory, repository, service.

The annotations here would be defined as meta-annotations (i.e. @Target(ElementType.ANNOTATION_TYPE)) only as they're used to qualify meta elements for either references. A downstream use case would be for tools to easily identify the different groups of concepts so that they can define general rules enforced on those without having to know about which of the actual meta elements belong to that group. A very fundamental rule example would be that newables must not depend on injectables but only the other way round.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.