Keeping business logic out of your UIs
-
Upload
petter-holmstroem -
Category
Software
-
view
127 -
download
0
Transcript of Keeping business logic out of your UIs
![Page 2: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/2.jpg)
What is “business logic”?
● Every information system exists to solve a real-world problem (I hope...)● A real-world problem consists of static parts (things, concepts) and dynamic
parts (events, processes)● A system uses a model of the real world to solve its problems
○ The domain model
● The static parts of the domain model are often the easy ones● The dynamic parts are easily forgotten even though they are just as important● The business logic is the implementation of the dynamic parts of the domain
model
![Page 3: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/3.jpg)
Disclaimer:Business logic creeping into the UI is not really an architectural problem but a problem with developer discipline
![Page 4: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/4.jpg)
Let’s look at a “classic” architecture
Persistence layer (JPA)
Service layer (EJB)
UI layer (Vaadin)
Entities
SQL database
![Page 5: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/5.jpg)
Problem 1
UI Operation
Service 1
Service 2
Service 3
Actual transactionboundaries
Logical transaction boundary
![Page 6: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/6.jpg)
Problem 2
UI CRUD Service+
Business logic in the user’s head and in the UI
Service layer is only a frontend to the database
![Page 7: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/7.jpg)
Problem 3
UI 1
UI 2
UI 3
God Service
![Page 8: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/8.jpg)
Problem 4
Service A Service B
New method
?
![Page 9: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/9.jpg)
What can we do?
![Page 10: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/10.jpg)
Think about the transaction boundary
● Pay attention while coding and while reviewing others’ code● The transaction boundary should IMO go between the UI and your backend● Rules of thumb:
○ One UI operation, one backend call○ One backend call, one transaction○ One transaction, one thread
● Imagine your backend is running on a remote machine and you want to minimize the traffic
![Page 11: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/11.jpg)
Take care of your services
● Strive for highly cohesive services● Avoid too general names like CustomerService● Instead, opt for more specific names like CustomerOnboarding● If you are adding a new service method and you find you could add it to more
than one service, you should probably create a completely new one or refactor the existing ones
![Page 12: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/12.jpg)
Separate reading and writing
● Place your queries in separate components● Create UI specific query components instead of adding more and more query
methods to existing ones● Allows for some neat optimizations and scaling
![Page 13: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/13.jpg)
Avoid CRUD
● CRUD UIs and services basically move the business logic into the head of the user
● Base your UIs and services on actual business processes and operations● Exception: management UIs for reference and master data
![Page 14: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/14.jpg)
Introducing a Command based architecture
![Page 15: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/15.jpg)
● Think in terms of Commands and Queries● A Command tells the system to perform a specific business operation
○ A command may return some result○ A command either completes successfully or fails with an error
● A Query asks the system for specific data○ A query always returns something○ A query only fails because of external runtime errors such as network problems
● Commands and queries can be synchronous or asynchronous● You can model each command and each query as a separate class
Forget about services!
![Page 16: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/16.jpg)
The query/command class
● The name is always a verb in its imperative form● The parameters are class attributes● Use a generic parameter for the result, if any● Try to make your class immutable
○ Not always possible, e.g. if you are binding a form directly to your command
● Validate the parameters inside your class○ If you do this in the constructor, you cannot create a command or query with invalid parameters
![Page 17: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/17.jpg)
Examples
<<command>>CreatePatient<Patient>
firstName: string
lastName: string
gender: Gender
birthDate: LocalDate
<<query>>FindOrders<List<Order>>
from: LocalDate
to: LocalDate
customer: Optional<Customer>
![Page 18: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/18.jpg)
Examples (code)
public class CreatePatient implements Command<Patient> {
final String firstName;
final String lastName;
final Gender gender;
final LocalDate birthDate;
public CreatePatient(String firstName, String lastname,
Gender gender, LocalDate birthDate) {
this.firstName = Objects.requireNonNull(firstName);
… }
}
![Page 19: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/19.jpg)
Examples (code)
public class FindOrders implements Query<List<Order>> {
final LocalDate from;
final LocalDate to;
final Optional<Customer> customer;
public FindOrders(LocalDate from, LocalDate to) {
… }
public FindOrders(LocalDate from, LocalDate to,
Customer customer) {
… }
}
![Page 20: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/20.jpg)
What about the implementation?
● Technically, queries and commands are implemented in the same way● Each command/query has a handler● The handler contains a single method that accepts the command/query as a
single parameter and returns the result of the command/query● Handlers are transactional● Similar queries/commands can share a common base class● Handlers can invoke other handlers
![Page 21: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/21.jpg)
Finding the correct handler
● A client will never invoke another handler directly● Instead, commands/queries are passed to a broker or gateway● The broker/gateway will look up the correct handler, invoke it and return the
result
![Page 22: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/22.jpg)
Advantages
● An easy way of modeling the dynamics of the problem domain● Forces you to think in terms of the domain while designing your UI
○ Since your UI should only be constructing and invoking commands/queries, the risk of business
logic ending up there should be smaller (I hope)
● Your business logic consists of small, highly cohesive classes● No more god classes● Easy to distribute, e.g. by using a service bus
○ Command and queries could be serialized into JSON○ Command and query handlers can be running anywhere
● Easy to run asynchronously● You can use separate data sources for reading and writing
○ CQRS
![Page 23: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/23.jpg)
Master SlaveSlave
Query Handler Query HandlerCommand Handler
Broker
UI
![Page 24: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/24.jpg)
Disadvantages
● More boilerplate code: for each operation, you have to write a command/query class and a handler class
● The client does not invoke the handler directly so if the handler is missing, it will not be detected until during runtime
● You have to write the command/query framework yourself● You can still write too coarse or too fine grained commands
![Page 25: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/25.jpg)
Time for a code example!
![Page 26: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/26.jpg)
What about long-running transactions?
● Many commands participate in the same conversation● If your container supports it, you can make your handlers conversation scoped
○ This makes it possible to store state in the handlers
● If you want your handlers to remain stateless, create a conversation object that is returned by and passed to every command handler
● The conversation object contains the state necessary to move the conversation forward
![Page 27: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/27.jpg)
Summary
● Discipline vs patterns● Transaction boundary● High cohesion● Separate read and write● Avoid CRUD● Consider using commands and queries in business driven user interfaces
![Page 28: Keeping business logic out of your UIs](https://reader034.fdocuments.us/reader034/viewer/2022042906/58a8c0f31a28ab53138b48a5/html5/thumbnails/28.jpg)
That’s all folks!