Our new project just started and we have a problem related to its architecture.
We have a 3 layer arhitecture:
WebUI
Business
DataRepositories
Each layer has reference only to the layer below it. The communication is done with what we call entities and business objects (BO) as follows:
DataRepositories <--entities--> Business <--BO--> WebUI
<--X--> means communication using objects of type X.
So we have for example UserEntity as entity and User as BO. Another type is ticket which again has TicketEntity and Ticket.
Currently we have some distinct vertical slices through the layers having something like Accounts for users in DataRepositories, Business and WebUI which are well defined and don't interact with the other slices like Tickets.
Now the problem is that a ticket has an buyer which is an user and we don't know where in our architecture we should connect tickets and users. Should the business components interact between them or the data layer should map the user to the ticket?
To be more specific, we have a method for creating a ticket that is resides in Business and is called from WebUI. It takes as arguments the details of a ticket and "the user" which we don't know yet if it should be an object of type user or just the username/id. If we pass a user object that the presentation should get the user before calling CreateTicket. But, if the webui passes the id then the business layer should resolve the user object which would require adding a reference to the Users business component in Tickets (Business).
Personally, I hate parallel hierarchies like this. You've created what you're calling entities, which should have some behavior associated with them, plus a parallel hierarchy of business objects that should be immutable and without any behavior.
I'd dispense with the business objects. I suspect that they aren't providing any value that you can cite besides immutability and someone else's notion of "architectural purity".
I also don't like the direction of the arrow between entities and repositories. I'd have the repositories know about entities, but not the other way around. Why should an entity know or care if it's persisted? The business logic and behavior should be unchanged.
I'd have the view layer interact with services. These are UI agnostic, but they contain all your business logic to fulfill use cases. If you throw away your UI - and you will every few years - your services will remain in place for as long as the business problem does.
The data layer should be responsible for its own referential integrity. If a ticket needs to JOIN to find its user, then you have to have it in the data layer. When the persistence tier queries for a user, it'll also get the tickets that belong to that user and return the one-to-may relationship in the objects. A User will have a List or Set of Ticket instances. All this should be done in the service layer. The service will orchestrate the persistence, business objects, and other services it needs to fulfill the use case.
Related
In an event-based microservice architecture what is best practice for querying for additional data needed for a microservice handling an event?
Imagine this microservice constellation:
OrderService - receives orders via REST, writes the order to the order database and issues an OrderCreatedEvent, which includes the order data and a customerId.
CustomerService - REST Api for managing customers by using its own customer database, creates an receives different events which are not relevant for the use case
VoucherService - listens to OrderCreatedEvents to sent vouchers to customers.
Here's the qestion: the VoucherService needs more information on the customer (e.g. the address) as is provided in the OrderCreatedEvent - what's the best way to provide the VoucherService with the customer data?
Possible Solutions:
The VoucherService could call the API of the CustomerService, but this violates the lose coupling of services.
The VoucherService could query the customer database, but this would lead to even tighter coupling as changes to the customer database now must be compatible to the VoucherService.
The OrderService could eventually be able to fill the necessary customer data to the event, but this only works if the data is available for some reason and additionally this will lead to problems because in an enterprise environment there could be 50+ fields for a customer and the OrderService doesn't know (and shouldn't know) which of them are necessary for its clients.
Any suggestions how to solve this?
The solution that you stated:
The OrderService could eventually be able to fill the necessary customer data to the event, but this only works if the data is available for some reason and additionally this will lead to problems because in an enterprise environment there could be 50+ fields for a customer and the OrderService doesn't know (and shouldn't know) which of them are necessary for its clients.
I would suggest to keep the OrderService dumb on customer data, but
since you need the customer data in the VoucherService, you
VoucherService should be interested on the events coming from
CustomerService and store the necessary data that are crucial for the service functionality
There are no silver bullets on solving everything perfectly, but keeping stuff async it will be always the best solution, this requires data duplication and more work, but in the end every service is decoupled and will work without problems on their own
I'm currently trying to build an application that handles personal finances. I'm struggling with Lagom ways of doing because I can't find any example of "real" application built with Lagom. I have to guess what are best practises and I'm constantly afraid of falling into pitfalls.
My case is the following: I have Users, Accounts and Transactions. Accounts belong to users but can be "shared" between them (with some sort of authorization system, one user is admin and other can read or edit the account). Transactions have an optional "debit" account, an optional "credit" account and an amount which is always positive.
The scenarios I was considering are the followings:
I consider that transactions belong to accounts and are parts of the account entity as a list of entries. In that scenario, a transfert transaction must have a "sister" entry in the other account. This seems easy to implement but I'm concerned by :
the potential size of the entity (and the snapshots). What happen if I have accounts that contain thousands of ten of thousands of transactions?
the duplication of the transaction in several accounts.
I consider that transactions have their own service. I that case I can use Kafka to publish events when transactions are recorded so the Account entity can "update" it's balance. In that case does it make sense to have a "balance" property in the entity or a read-side event listener for transaction events that update the read-database?
I can have two Persistent Entities in the same service but in that case I'm struggling with the read-side. Let say I have a transaction, I want to insert into the "transactions" table and update the "accounts" table. Should I have multiple read-side processors that listen to different events but write in the same db?
What do you think?
I think that you shouldn't have a different entity 'Transactions' because it is tightly coupled to the account entity, in fact, the transactions of an account is no more than the event log of this account. So I recommend persisting the balance with a unique transaction id and the id of the other account when it is a transfer transaction, and make the read processor to listen the events of the account changes to store them in the read model.
Doing this, a transfer is just a message between the two accounts that results in a modification of the balance that later will be persistent as part of the event log of each of them. This way seems more natural and you don't have to manage a sepparate aggregate root that, in addition, is tightly coupled to the account entities.
We want to add an UpdateDatetime column in a SQL database, when an entry is changed.
In Microservices Architecture, (a) would all 3 services which access the table, need to now include Updatedate in their API, (b) Or would Microservices share a same DataAccess Layer?
If letter (a), is their any method to make development easier?
We are inquiring about developer maintenance associated with Microservices, since we may have 10 applications which interact with 1 table. If something is wrong in the table or column is added, we need to look/modify code through 10 app locations, as opposed to 1 location in Service Oriented Architecture.
The question is a little off because the diagram in (a) actually doesn't make much sense but given the domain and what I understand. I think the proper solution is that you'll have the order service at the same level as your other microservices, customer management, warehouse management, and order fulfillment in this case. In total, that'll be four microservices.
When an order is created, it can propagate a message to a message bus where the other three services that are interested in servicing the order will get the event and update the order accordingly. If there are different steps to complete the order, you can also pipeline this with something like a queue where it moves from one topic to another where the respective service will update it accordingly.
In our project we're trying to apply the Bounded Context ideology and we've faced kind of obvious problem of performance. E.g., we have different classes (in different contexts) for representing a user in the system: Person in our core domain's context and User in security context. So, we have two different repositories for each of the aggregate, but they are using the same table in DB and sometimes accessing the same data.
Is there common solution to minimize db roundtrips in this case? Are there ORM's which deals with it, or should we code some caching system by ourselves?
upd: the db is from legacy app, and we'll have to use it "as is"
So, we have two different repositories for each of the aggregate, but
they are using the same table in DB and sometimes accessing the same
data.
The fact that you have two aggregates stored in the same table is an indication of a problem with the design. In this case, it seems you have two bounded contexts - a BC for the core domain (Person is here) and an identity/access BC (User is here). The BCs are related and the latter can be seen as upstream from the former. A Person in the core domain has a corresponding User in the identity BC, but they are not exactly the same thing.
Beyond this relationship between the BCs there are questions regarding ownership of behavior. For example, both a Person and a User may have a name and what is to be determined is who own's the behavior of changing a name. This can be implemented in several ways. Person may have its own name and changes should be propagated to the identity BC. Similarly, User may own changes to name, in which case they must be propagated to Person via a synchronization mechanism.
Overall, your problem could be addressed in two ways. First, you can store Person and User aggregates in different tables. Any given query should only use one of these tables and they can be synchronized in an eventually consistent matter. Another approach is to decouple the behavioral domain model from a model designed for queries (read-model). This way, you can create a read-model designed to serve a specific screen(s) and have a customized query, perhaps even outside of an ORM.
If all the Users are Person too (sometimes external services are modeled as special users too), the only data that User and Person should share on the database are their identifiers.
Indeed each entity in a domain model should hold references only to the data that they need to ensure their invariants.
Moreover I guess that Users are identified by Username and Persons are identified by something else (VAT code or so..).
Thus, the simplest optimization technique is to avoid to encapsulate in an entity those informations that are not required to ensure its invariants.
Furthermore you simply need an effective context mapping technique to easily pass from User to Person when needed. I use shared identifiers for this.
As an example you can expose the Person's identifier in the User class, so that a simple query to the Person's repository can provide you the data you need.
Finally I suggest you the Vaughn Vernon series on Aggregate Root Design.
How closely does your data model map to your UI and domain model?
The data model can be quite close to the domain model if it has, for example, a Customer table, an Employee table etc.
The UI might not reflect the data model so closely though - for example, there may be multiple forms, all feeding in bits-and-pieces of Customer data along with other miscellaneous bits of data. In this case, one could you have separate tables to hold the data from each form. As required the data can then combined at a future point... Alternatively one could insert the form data directly into a Customer table, so that the data model does not correlate well to the UI.
What has proven to work better for you?
I find it cleaner to map your domain model to the real world problem you are trying to solve.
You can then create viewmodels which act as a bucket of all the data required by your view.
as stated, your UI can change frequently, but this does not usually change the particular domain problem you are tackling...
information can be found on this pattern here:
http://blogs.msdn.com/dphill/archive/2009/01/31/the-viewmodel-pattern.aspx
UI can change according to many needs, so it's generally better to keep data in a domain model, abstracted away from any one UI.
If I have a RESTful service layer, what they are exposing the domain model. In that case , the UI(any particular screen) calls a number of these services and from the domain models collected composes the screen. In this scenario although domain models bubble all the way up to UI the UI layer skims out the necessary data to build its particular screen. There are also some interesting questions on SO about on using domain model(annotated) for persistence.
My point here is the domain models can be a single source of truth. It can do the work of carrying data , encapsulating logic fairly well. I have worked on projects which had a lot of boilerplate code translating each domain model to DTO, VO , DO and what-have-yous. A lot of that looked quite unnecessary and more due to habit in most cases.