xmolecules / jmolecules Goto Github PK
View Code? Open in Web Editor NEWLibraries to help developers express architectural abstractions in Java code
Home Page: http://jmolecules.org
License: Apache License 2.0
Libraries to help developers express architectural abstractions in Java code
Home Page: http://jmolecules.org
License: Apache License 2.0
The use of compile
to declare Gradle dependencies has been deprecated for a while and as far as I know even removed from Gradle 7.x
(See https://docs.gradle.org/current/userguide/upgrading_version_5.html)
So in the documentation, use implementation
to declare the Gradle dependencies instead.
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?
Bounded Contexts can be implemented in different ways: as packages, deployment units, microservices. With this annotation the developer could express that a Java package or Jigsaw module implements a Bounded Context.
See https://domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf, section "Bounded Context".
Spring module is missing. jdd-archunit
-> jddd-archunit
.
Hi!
I would like to use the library in a Intellij Java project which uses Java 9 modules. The problem is that if a library doesn't declare an Automatic-Module-Name
in the Jar MANIFEST the library falls into the unnamed module, and as we speak, Intellij does not support unnamed module.
It's quite an easy addition, as described in Automatic-Module-Name: Calling All Java Library Maintainers.
Thanks for this library!
It would be cool, if Association allowed to directly check whether it points to a particular Aggregate
or Identifier
.
@EventSubscriber, @EventPublisher, @command
jmolecules-architecture-layered
-> jmolecules-layered-architecture
jmolecules-architecture-onion
-> jmolecules-onion-architecture
The DDDBITS provide two kinds of things:
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);
}
}
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.
Especially @ApplicationService. But @usecase would also be interesting.
@EventSubscriber and @EventPublisher is probably better fitted in jddd-events than in jddd-core. I'l open another issue for that...
Similar to the JPA plugin (see #8) we could translate jDDD annotations into their Spring equivalents.
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:
We currently only expose an @Repository
annotation but should actually also provide a type based equivalent.
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)?
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
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:
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?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.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:
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).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.There are branches that explore the feasibility of this:
hacking/ddd-generics
– the actual model changeshacking/ddd-generics
– adapting technology integration and integration testshacking/jmolecules-generics
– adapted domain model to see the effects of the moveThe jddd.org repo link resolves to a Plesk page:
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
See https://domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf, section "Layered architecture".
It needs to be further discussed if we should add annotations specific for event sourcing, i.e.
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:
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/
org.jmolecules:jmolecules-…
See this blog article for which rules we should expose by default.
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;
}
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 annotationAxon 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.
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.@EventHandler
but we have chosen @DomainEvent
in the jddd-events
module. Thus, I'd vote to name the corresponding handler annotation @DomainEventHandler
for consistency.@ViewModel
or @Projection
? I tend to vote for the former.Currently, value objects need to be marked by an annotation, as no interface exists to declare them.
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 typeThis 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.
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.
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
In their implementations, DDD building blocks have a well defined mapping towards who is managing the lifecycle of them. Two concepts can be found:
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.
Based on the @Layer
annotation, suggested in #3, we should add annotations for the Onion Architecture, similar to jQAssistant's DDD Plugin.
This should probably be a separate artifact (at least a separate package) as there's valid use of the DDD building blocks in the context of other architectural approaches.
See https://domainlanguage.com/wp-content/uploads/2016/05/DDD_Reference_2015-03.pdf, section "Domain Events".
User Story
As a reader of the Javadoc documentation I want fast identify the architecture of a project.
UAC
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.