Why is Pattern Open Session In View considered an anti-pattern?

Asked

Viewed 2,476 times

4

I wonder why many developers and architects consider the standard Open Session In View one anti-pattern?

1 answer

8

What is Open Session In View?

It is a standard used with frameworks of Object-Relational Mapping like Hibernate and other JPA implementations.

An object managed by a JPA framework is known as Entity. An entity may have relationships with other entities and these relationships are automatically resolved by the framework.

The problem is that data from related entities by default is recovered only when effectively the code executes the method that recovers the value. If the call is made after the connection to the bank has been terminated the famous error occurs LazyInitializationException or equivalent.

In the pattern Open Session In View, the "session" (connection ) is open until the end of the request, allowing the relationship data to be recovered at any time, including during the rendering of the View, because it is a time when many data are accessed.

When this pattern is used?

For example, if there are two views that use the same service to retrieve an entity, but only one of them accesses another related entity, the solutions could be:

  1. Always upload the data of this relationship, but it is a waste because it is known that in some situations the data will be unnecessary.
  2. Create another service that already returns relationship data, however this can lead to duplicate code.
  3. Allow data to be recovered outside the service. This is the default! It means when a View access, for example, cliente.getEndereco() the framework will fetch the customer address in the database.

Why is he a anti-pattern?

It "breaks" the encapsulation of the layers of architecture.

You’ll need code implemented in the Control or View layer to manage connection and transaction with the database.

In addition to breaching the "least knowledge possible" principle, we have a strong coupling between the View code and the services available on core of the system.

This can make it difficult to carry out unit tests and reuse services elsewhere.

Performance and scalability may be affected

The default requires that the transaction and, consequently, the database connection remain open until the end of the request. But holding such an essential resource can cause huge impacts on system performance, especially if there are multiple simultaneous accesses.

By making a very crude guess, we could say that if the transactions take twice as long to be completed because of the generation time of the view, the system will be able to serve half of the users compared to a version that closes the transaction in the service layer.

It’s just that this is usually a lot worse. If the transaction remains open during the view, it may be blocking important features of several other users. Transactions should be closed as soon as possible.

I worked on a system that had a "heavy" processing of about a minute. In theory it would work in parallel, but we noticed that all requests from different users were being queued. The reason? A lock in a table caused by the ID increment at the beginning of the service. The resolution was simple: perform heavy processing outside the transaction.

Lack of transparency

When the session is "loose" during the request, it is easier for problems to go unnoticed. The developer gets comfortable knowing that their entities can do "everything" after they are returned by the service layer.

The trend is that the number of queries executed during the rendering of the views increases without control. Until the system starts being used in production by multiple users, this problem will go totally unnoticed.

Unless the developer is always logged in and analyzed all generated queries. And this should be done whenever the view change, as new calls to new attributes can cause new queries to be executed at any time!

A JSP with a seemingly innocent EL can actually occupy 99% of the response time.

He’s used for sloth

It may be lazy to refactor services, to argue with other developers to create a better architecture, to study a better standard and so on.

The point is that the service layer should return the data ready for the view in a way that does not require additional processing. Only, the developer would need to analyze the data and see what will be required.

So, just as it’s easier to create a global variable to use everywhere, leave the session open to be used "when necessary".

Dealing with errors

If the transaction is completed after rendering the View, this treats a greater complexity for handling possible errors.

Imagine that while a screen is generated an error occurs in one of the queries, perhaps because the column of a table has been deleted. How this will be treated?

In a web application, for example, this will require a filter to handle this type of error.

Exceptional cases are a big problem

Imagine that a particular service needs to read data from one database to another. This will require two connections and perhaps a distributed transaction.

The problem is that its architecture is already engaged, so it would have to be done some gambiarra to open another connection, with another transaction unlinked from the first, or something like.

Conclusions

Particularly, I see no advantages and situations where it would be necessary to use the standard Open Session In View.

On the other hand, in Desktop applications it could be used without major problems because there is the issue of competition and scalability cited, although the separation of layers continues to be broken.

From my point of view, the developer should worry about what data will be used after the call of each service and force this, for example using fetch joins.

And patterns like Transfer Object are our friends at these times when we need to bring data to the bank without altering our entities or abusing the use of relationships.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.