Git Product home page Git Product logo

fakedci's Introduction

Fake DCI

A compromise that aims to keep the Use Case orientation of DCI when OOP is de-emphasized

If you are new to Data-Context-Interaction:

A bit of context

Unfortunately, in recent years we've seen a tendency of de-emphasis (or sometimes even bashing) of OOP. This is true at least in the area of web/enterprise applications. While there's more than one cause for the phenomenon, the misuse of OOP over time (which DCI aims to fix) has certainly had its influence. This other example aims to provide a Java implementation that's closer to the DCI philosophy, however it may be met with resistance. In case of Java web apps, it's quit common to see the approach of having simple ("anemic") JPA entities, with the business logic being housed in stateless service methods. This becomes especially problematic when the services are entity-aligned (rather than use case aligned), leading to difficulties identifying functionality implementation and service classes that become ever-so-large (because the same entity may be used in several use cases). In such situations, we may still be able to keep some of the benefits of DCI - namely the use case orientation - even though we loose the object enrichment capabilities.

Approach taken

First and foremost, we need to let go of entity-aligned (large) services and switch the focus on use cases. Therefore, we will have miniature (I won't use the word "micro") domain services that only contain the business logic associated with an entity in a given use case. The Spring framework is most commonly encountered in Java web apps and so the @Service annotation is usually used. In this example however, I propose defining new @Component based stereotypes that clearly express the relation to DCI concepts. For example:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface DciRole
{
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

https://github.com/alexbalmus/fakedci/blob/master/src/main/java/com/alexbalmus/fakedci/dcibankaccounts/stereotypes/DciRole.java

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface DciContext
{
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";
}

https://github.com/alexbalmus/fakedci/blob/master/src/main/java/com/alexbalmus/fakedci/dcibankaccounts/stereotypes/DciContext.java

Now, assuming we have an entity of type Account (or a subclass), we will annotate the "role" miniature domain services and define them like so:

@DciRole
public class Account_DestinationRole<A extends Account>
{
    public void receive(A destination, final Double amount)
    {
        destination.increaseBalanceBy(amount);
    }
}

https://github.com/alexbalmus/fakedci/blob/master/src/main/java/com/alexbalmus/fakedci/dcibankaccounts/usecases/moneytransfer/Account_DestinationRole.java

@DciRole
@RequiredArgsConstructor
public class Account_SourceRole<A extends Account>
{
    private final Account_DestinationRole<A> accountDestinationRole;
    String INSUFFICIENT_FUNDS = "Insufficient funds.";

    void transfer(final A source, final A destination, final Double amount)
    {
        if (source.getBalance() < amount)
        {
            throw new BalanceException(INSUFFICIENT_FUNDS); // Rollback.
        }
        source.decreaseBalanceBy(amount);
        accountDestinationRole.receive(destination, amount);
    }
}

https://github.com/alexbalmus/fakedci/blob/master/src/main/java/com/alexbalmus/fakedci/dcibankaccounts/usecases/moneytransfer/Account_SourceRole.java

These "roles" will be played by Account (or subtype) entities inside the MoneyTransferContext (use case):

@DciContext
@RequiredArgsConstructor
public class MoneyTransferContext<A extends Account>
{
    private final Account_SourceRole<A> accountSourceRole;

    public void execute(final A source, final A destination, final Double amount)
    {
        accountSourceRole.transfer(source, destination, amount);
    }
}

https://github.com/alexbalmus/fakedci/blob/master/src/main/java/com/alexbalmus/fakedci/dcibankaccounts/usecases/moneytransfer/MoneyTransferContext.java

As mentioned, this approach is to be viewed as a compromise that looses some benefits of both DCI and OOP, and should only be used in situations where the more DCI-savvy approach is met with resistance.

fakedci's People

Contributors

alexbalmus avatar

Watchers

 avatar

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.