11 Haziran 2019 Salı

Yazılım Mimarisi - Layered Architecture

Giriş
Bu yazılım mimari benim en sık gördüğüm örnek. Genellikle 3-Tier Design olarak karşımıza çıkar. Açıklaması şöyle
There are different flavors of Layered Architectures and there’s no rule that determines how many layers should exist. The most common pattern is the 3 tier architecture, where the application is split into Presentation Layer, Logic Layer, and Data Layer.
Katmanlar
Açıklaması şöyle. Uygulama yatay (horizontal) katmanlara bölünür.
Presentation -> Business Logic -> Persistence olarak ayrılıyor.
The basic idea of the Layered Architecture is to split the application into at least three distinct areas of code: Presentation, Business Logic and Persistence, where Presentation can access Business Logic and Business Logic code can access Persistence, but not the other way around.
Tipik bir akış şöyle
Event fired in UI, traverse to a method in the BLL, perform logic (possibly in multiple parts of the BLL), eventually to the DAL, back to the BLL (where likely more logic) and then return some value to the UI.
Bu mimari ilk olarak 1990'larda ortaya çıkmış. Açıklaması şöyle.
When modern enterprise development took off in the 90s, it was quite normal to develop “everything” the enterprise needed in one or at most a few monolithic applications. The Waterfall Model was the de-facto process for software development.

Of course the development team necessary for such projects became too big eventually to work properly, so people thought about how to scale organizationally. Having the mindset described above, they came up with the idea of splitting up the application based on technology. There was a “frontend” team, a “backend” team, maybe even a “middleware” or “database” team.

In this setting the Layered Architecture fits very well, because the interfaces between the layers could be more or less changed to remote calls. So the different “horizontal slices” of the application could be “independently” developed.
Katmanlar Arasında Data Transfer Object (DTO) Kullanılır
Açıklaması şöyle. Buna aslında Data Oriented API deniliyor.
This design became prevalent in the late 90s, when a lot of developers transitioned from traditional procedural languages like C, Pascal, and Basic to Java. Sometimes, the DTOs were called Value Objects at the time, but regardless of what they were called, they were the familiar data structures we've grown accustomed to previously. It was a popular approach and easy to understand because it didn't really require a change of mindset.

Eleştiriler

1. Business Logic Katmanının Her Tarafa Bulaşması
Business Logic Katmanının GUI katmanından bağımsız olması gerektiği varsayımının yanlış olduğu söyleniyor. Varsayım şöyle.
One of the more practical arguments for a layered design is, that it creates a Separation of Concerns. It means that the business logic to transfer money from one account to the other should not concern itself with what color it will have on the Web GUI.

This argument sounds reasonable on the surface, however it implies more than what it says. It is almost always interpreted as all presentation-related logic should be separated out of “business logic”. Not just colors and font-sizes, but everything. 
Bu varsayımı çürüten açıklama şöyle.
This obviously does not reflect reality, as business-related things do tend to have a UI and do tend to have persistence. An Account, Amount, Transfer, etc. does need to be presented in addition to fulfilling other functions. How does Layered Architecture address this apparent conflict? It doesn’t really. It usually uses anemic objects to push the data of an Account, Amount, etc. to other layers, so it can be presented or used. It smears business related knowledge all over the application, because everything has to understand the data for themselves. The Presentation needs to understand what an account is, how to ask for it from the user, how to create the object and with what parameters. Repeat for all other layers.
Yani BL ile UI arasında aslında BL tarafında kalması gereken ancak UI katmanını işlemesi için gerekli bir sürü nesne/bilgi daha ister istemez, UI katmanına gönderiliyor.

Bu yüzden de uygulamayı idame ettirmek zorlaşıyor. Açıklaması şöyle. Yani aslında katmanlar iç içe geçmeye başlıyor.
Many applications have two ends: a user-side and server-side, often designed in two, three, or n-layers architecture. The main problem with n-layered architecture is the layer lines are not taken seriously, causing application logic to leaks across the boundaries. This entanglement between the business logic and the interaction makes it impossible or difficult to extend or maintain the application.
Örneğin uygulamamız konsoldan kullanılıyor olsun. Eğer Web'den de kullanılıyor olsun istersek işler karışabilir.

Hexagonal Mimari uygulamayı kullanabilen/sürebilen bir başka arayüz takılmasını bir nebze kolaylaştırabiliyor

2.1 Sebep Data Transfer Object Kullanılması mı ?
Buradaki eleştiri katmanlar arasında Data Transfer Object'lerin olması değil. Eleştiri bu nesnelerin  klasik Object Oriented kodlar olmaması. Açıklaması şöyle.
One of the core principles of Functional Programming is pure functions.

One of the core principles of Object Oriented Programming is putting functions together with the data they act on.

Both of these core principles fall away when your application has to communicate with the outside world. Indeed you can only be true to these ideals in a specially prepared space in your system. Not every line of your code must meet these ideals. But if no line of your code meets these ideals you can't really claim to be using OOP or FP.

So it's OK to have data only "objects" that you fling around because you need them to cross a boundary that you simply can't refactor to move the interested code across. Just know that isn't OOP. That's reality. OOP is when, once inside that boundary you gather all the logic that acts on that data into one place.
Dolayısıyla DTO eğer ekranda gösterilecekse display(), displayEditable() gibi metodlarının olması gerekiyor deniliyor. Böylece BL değişince, UI etkilenmez çıkarımı yapılıyor.

3. Çünkü Data Transfer Object'in BL ve UI Tarafından Ayrı Ayrı Yorumlanıyor
Açıklaması şöyle.
The biggest problem with data-oriented interfaces is that they share meaning implicitly. This is not the good kind of sharing either. It means that because the communication is reduced to data, both sides must have the appropriate interpretation for that data, which might include anything from simple things like what values it could have (can it be null?) to complex interrelations between different parts (like the 1/100th flag above).

If both sides must possess this knowledge then it follows that both sides have to change when this interpretation changes. To make it worse, the interpretation is implicitly shared, because there is no way to detect if suddenly other rules or interactions apply to the data, so there will be very limited language and IDE support for implementing the change. The only way to prevent this outcome is to keep this knowledge localized and hidden as much as possible.
Sonuç - Katmanlar Arasında Mantıksal ve Gözle Görünmeyen Bağımlılıkların Olması
UI'daki herhangi bir değişikliğin BL katmanından başlayarak her yeri etkilemesi. Açıklaması şöyle.
The Business Logic defines the data the Presentation receives, usually in the form of Data Transfer Objects, which are pure data structures. Any modification on the Presentation side other than trivial color changes will need additional (or less) data or data that is structured differently, or paged differently, etc. In other words the Business Logic will respond to Presentation changes. Although there will be no physical dependency seen in code, there will be an invisible semantic dependency that runs from Presentation to Business Logic.

The same with Persistence. The Business Logic can only use things which the Persistence Layer offers. So if a new query is needed or a new update statement for a new use-case, the usual approach is to just implement it in the Persistence and use it in the Business Logic Layer. Again, no physical dependencies are there, but there are always changes in Persistence happening because of Business Logic changes or needs.
Basit bir örnek şöyle.
If you want to change an Account, for example introduce a “known/unknown”-flag or change the account number to an IBAN, or even support a different Account type, you’ll have to hunt down and change each and every piece of code that receives any data associated with the Account. You’ll have to change the “UI” of the Account for sure, the Business Logic how to handle it, and of course the Persistence to store it. You will very likely have changes in all layers. This amount of work seems to be surprisingly large, when the actual change only seems to involve a single business concept.

Everyone who had the unfortunate task to “simply add a new field to this page” in such an architecture already knows how difficult this task can be.
İyileştirme Denemesi - İlişkiyi Anlamak İçin Package By Feature
Package By Feature yazısına taşıdım.

Çözüm Denemesi - Pure Object Oriented Yaklaşım
Layered Architecture'a karşı çıkanlar genellikle pure OO yaklaşımı savunuyor. Bu yaklaşım EJB 2 ile denendi ancak başarısız oldu. Açıklaması şöyle.
The best example of this is the failed design of the EJB 2 entity beans. An entity bean represents a business model. Typically models have to be persistent and EJB 2 entity beans tried to support this behavior. That looked fine from a OO point of view but not from a Separation of Concerns point of view. In order to support this behavior over the wire, each EJB 2 Entity Bean was in fact a RMI stub with its own RMI connection to the backend server. You can imagine how badly that scaled when in a typical screen of a typical application you are dealing with hundreds of entities at any time (think a simple data table).

What happened was that entities have narrow scope. Most of the times they are request scoped. They also processed in large numbers, they can typically scale up to millions of records in the database and up to hundreds at a single use case.

Hiç yorum yok:

Yorum Gönder