クリーンアーキテクチャデザインパターン

バーニースティンソン:

ここでは、画像の説明を入力します。

https://8thlight.com/blog/uncle-bob/2012/08/13/the-clean-architecture.html

私はこのパターンについていくつか質問があります。データベースはoutter層であるが、どのように実際にその仕事をしませんか?例えば、私はちょうどこのエンティティをmangesことMicroservicesがあるとします。

person{
  id,
  name,
  age
}

そして、使用例1は、人を管理することになります。管理者は、/ ..者(=> CRUD操作)を取得/保存しているが、これを行うにはユースケースでは、データベースに話をする必要があります。しかし、それは依存関係規則の違反となり

このアーキテクチャの作業を行いオーバーライドルールは依存関係のルールです。このルールは、ソースコードの依存関係のみが内側に指し示すことができると述べています。

  1. これも、正当なユースケースでしょうか?
  2. そのoutter層であればどのように私は、データベースにアクセスすることができますか?(依存IVERSION?)

私が出た場合GET /person/{id}の要求を私Microservicesはこのようにそれを処理する必要がありますか?

ここでは、画像の説明を入力します。

しかし、依存関係の反転を使用しての違反となり

内側の円の中には何も外側の円内のすべてについて何かで何かを知ることはできません。具体的には、外側の円の中で宣言何かの名前は、内側の円内にあるコードで言及されてはなりません。これは、関数、クラス、含まれています。変数、または任意の他の名前のソフトウェアエンティティ。


Crossing boundaries. At the lower right of the diagram is an example of how we cross the circle boundaries. It shows the Controllers and Presenters communicating with the Use Cases in the next layer. Note the flow of control. It begins in the controller, moves through the use case, and then winds up executing in the presenter. Note also the source code dependencies. Each one of them points inwards towards the use cases.

We usually resolve this apparent contradiction by using the Dependency Inversion Principle. In a language like Java, for example, we would arrange interfaces and inheritance relationships such that the source code dependencies oppose the flow of control at just the right points across the boundary.

For example, consider that the use case needs to call the presenter. However, this call must not be direct because that would violate The Dependency Rule: No name in an outer circle can be mentioned by an inner circle. So we have the use case call an interface (Shown here as Use Case Output Port) in the inner circle, and have the presenter in the outer circle implement it.

The same technique is used to cross all the boundaries in the architectures. We take advantage of dynamic polymorphism to create source code dependencies that oppose the flow of control so that we can conform to The Dependency Rule no matter what direction the flow of control is going in.

Should the Use Case layer Declare an Repository Interface which will be implemented by the DB Package (Frameworks & Drivers Layer)

ここでは、画像の説明を入力します。

If the Server recieves a GET /persons/1 Request the PersonRest would create a PersonRepository and would pass this Repository + the ID to the ManagePerson::getPerson Function, getPerson doesnt know PersonRepository but knows the interface it implements so its doesnt violate any rules right? ManagePerson::getPerson would use that Repository to look for the entity and would return a Person Entity to PersonRest::get which would return a Json Objekt to the Client right?

English is sadly not my native language so i hope you guys can let me know if i understood the pattern correct and maybe answer some of my questions.

Ty in advance

René Link :

The Database is at outter Layer but how would that work in reality?

You create a technology independent interface in the gateway layer and implement it in the db layer. E.g.

public interface OrderRepository {
    public List<Order> findByCustomer(Customer customer);
}

implementation is in the db layer

public class HibernateOrderRepository implements OrderRepository {
      ...
}

At runtime the inner layers get injected with the outer layers implementations. But you don't have a source code dependency.

You can see this by scanning your import statements.

And one of the use cases would be manage Persons. Manage Persons is saving / retrieving / .. Persons (=> CRUD operations), but to do this the Usecase needs to talk to a database. But that would be a violation of the Dependency rule

No, that would not violate the dependency rule, because the use cases define the interface they need. The db just implements it.

If you manage your application dependencies with maven you will see that the db jar module depends on the use cases not vice versa. But it would be even better to extract these use cases interface into an own module.

Then the module dependencies would look like this

+-----+      +---------------+     +-----------+
|  db | -->  | use-cases-api | <-- | use cases |
+-----+      +---------------+     +-----------+

that's the inversion of dependencies that would otherwise look like this

+-----+      +-----------+
|  db | <--  | use cases |
+-----+      +-----------+

If i get a GET /person/{id} Request should my Microservices process it like this? ここでは、画像の説明を入力します。

Yes that would be a violation, because web layer accesses the db layer. A better approach is that the web layer accesses the controller layer, which accesses the use case layer and so on.

To keep the dependency inversion you must decouple the layers using interfaces like I showed above.

So if you want to pass data to an inner layer you must introduce an interface in the inner layer that defines methods to get the data it needs and implement it in the outer layer.

In the controller layer you will specify an interface like this

public interface ControllerParams {
    public Long getPersonId();
}

in the web layer you might implement your service like this

@Path("/person")
public PersonRestService {

    // Maybe injected using @Autowired if you are using spring
    private SomeController someController;

    @Get
    @Path("{id}")
    public void getPerson(PathParam("id") String id){
       try {
           Long personId = Long.valueOf(id);

           someController.someMethod(new ControllerParams(){
                public Long getPersonId(){
                    return personId;
                }
           });
       } catch (NumberFormatException e) {
           // handle it
       }
    }
}

At the first sight it seems to be boilerplate code. But keep in mind that you can let the rest framework deserialize the request into a java object. And this object might implement ControllerParams instead.

If you consequently follow the dependency inversion rule and the clean architecture you will never see an import statement of a outer layer's class in an inner layer.

The purpose of the clean architecture is that the main business classes do not depend on any technology or environment. Since the dependencies point from outer to inner layers, the only reason for an outer layer to change is because of inner layer changes. Or if you exchange the outer layer's implementation technology. E.g. Rest -> SOAP

So why should we do this effort?

Robert C. Martin tells it in chapter 5 Object-Oriented Programming. At the end in the section dependency inversion he says:

With this approach, software architects working in systems written in OO languages have absolute control over the direction of all source code dependencies in the system. Thay are not constrained to align those dependencies with the flow of control. No matter which module does the calling and which module is called, the software architect can point the source code dependency in either diraction.

That is power!

I guess developers are often confused about the control flow and the source code dependency. The control flow usually remains the same, but the source code dependencies are inversed. This gives us the chance to create plug-in architectures. Each interface is a point to plug in. So it can be exchanged, e.g. for technical or testing reasons.

EDIT

gateway layer = interface OrderRepository => shouldnt the OrderRepository-Interface be inside of UseCases because i need to use the crud operations on that level?

I think that it is ok to move the OrderRepository into the use case layer. Another option would be to use the use case's input and output ports. The use case's input port might have repository-like methods, e.g. findOrderById, and adapts this to the OrderRepository. For persistence it can use methods that you define in the output port.

public interface UseCaseInputPort {
    public Order findOrderById(Long id);
}

public interface UseCaseOutputPort {
    public void save(Order order);
}

単に使用することの違いは、OrderRepositoryユースケースポートのみユースケース特定のリポジトリ方法を含んでいることです。ユースケースが変更された場合このように、彼らは唯一の変更します。単一責任を持っていて、インターフェイス分離の原則を光栄彼らはそう。

おすすめ

転載: http://43.154.161.224:23101/article/api/json?id=136784&siteId=1