Derinlemesine yazılım eğitimleri için kanalımı takip edebilirsiniz...

Vertical Slice Architecture Nedir? Derinlemesine İnceleyelim…

Merhaba,

Bu içeriğimizde, bir yazılım sistemini UI, Business Logic, Data Access vs. gibi yatay katmanlara bölmek yerine, her bir işlevselliği baştan sona dikey bir şekilde organize edebilmemizi sağlayacak olan Vertical Slice Architecture yaklaşımını teorik ve pratik çerçevede derinlemesine inceleyecek ve değerlendireceğiz.

Vertical Slice Architecture Nedir?

Vertical Slice Architecture; bir uygulamayı, her biri bağımsız bir işlevselliği temsil edecek şekilde dikey dilimlere bölmemizi sağlayan farklı bir yaklaşımdır. Her dilim, belirli bir özelliği(feature) veya iş akışını baştan sona, diğerlerinden olabildiğince bağımsız paketler olarak kapsamakta ve böylece sistemin farklı işlevlerinin birbirlerini çok az etkilemesini sağlamaktadır.

Vertical Slice Architecture’ın Layered Architecture’dan Farkı Nedir?

Vertical Slice Architecture Nedir? Derinlemesine İnceleyelim...Vertical Slice Architecture’ı anlayabilmek için öncelikle geleneksel katmanlı mimarinin yapısını anlamak gerekmektedir.

Malumunuz, geleneksel katmanlı mimaride kod, işlevine göre ayrılmış katmanlardan oluşmaktadır. Misal olarak; tüm kullanıcı arayüz kodları Presentation katmanında, iş kuralları Business katmanında ve veritabanı erişim işlemleri de Data Access katmanındadır. Bu geleneksel yaklaşım, yatay dilimler mantığında yandaki gibi düşünülebilir.

Yani sistemde bir özelliği hayata geçirebilmek için yukarıdan aşağıya ilişkisel bir şekilde bu katmanların içinden geçmek gerekir. Bu yüzden yatay katmanlar denmektedir.

Aynı şey Onion Architecture için de geçerlidir. Bu mimaride de katmanlar daire şeklinde birbirlerinden soyutlanmıştır, bu nedenle sadece mimarisel çizim tarzı farklı olsa da, akış yine aynı şekilde yatayda işlevsellik göstermektedir.

Vertical Slice Architecture ise yukarıda bahsedildiği gibi bu yaklaşımın tam tersi bir bakış açısı sunmakta ve kodu, özelliğe göre gruplandırarak çalışma ortamı sağlamaktadır.Vertical Slice Architecture Nedir? Derinlemesine İnceleyelim...Örnek vermemiz gerekirse eğer bir ‘sipariş oluşturma’ işlemi için gereken UI, iş kuralı ve veri erişimi çalışması için gerekli operasyonların hepsi aynı dilim içinde paketlenir.

Sipariş Oluşturma Slice Sipariş İptali Slice
Controller / Endpoint
Business Rule
Repository
Controller / Endpoint
Business Rule
Repository

Benzer mantıkla ‘sipariş iptali’ işlemi ise tamamen ayrı bir dilimdir. Yani anlayacağınız, geleneksel katmanlı mimarilerde işlevine göre yatay ayrım söz konusuyken, Vertical Slice’da ise özelliğe göre dikey ayrım mevzu bahistir.

Bunu şöyle bir metaforla da özetleyebiliriz; yatay katmanlı mimaride, pizza malzemelerine göre ayrılır. Hamur bir yerde, peynir bir yerde, domates bir yerde… Vertical slice mimaride ise pizza dilim dilim kesilerek her dilimde hamur, peynir ve domates olması sağlanır.Vertical Slice Architecture Nedir? Derinlemesine İnceleyelim...Dolayısıyla geleneksel katmanlı mimaride katmanlar arası bağımlılık olduğu için bir noktadaki değişiklik çoğu zaman birden fazla katmanda değişiklik gerektirmektedir. Bu bağımlılık zincirinden kaynaklı değişiklikler ister istemez katmanlar arasında yayılmaktadır. Vertical Slice Architecture ile tüm ilgili kod tek bir yerde, o özelliğin diliminde(slice) bulunmaktadır ve katmanlardan ziyade, özellik ekseninde ayrım yapılmaktadır.

Benzer mantıkla her şeyin domain merkezli olarak katmanlardan geçtiği Onion Architecture’da da, Vertical Slice Architecture ile her işlevin kendi mini domain’i oluşturularak, kod organizasyonu özellik tabanlı olacak şekilde tasarlanır.

Vertical Slice Architecture’ın Layered Architecture’a Nazaran Çözdüğü Sorunlar Nelerdir?

Biliyorsunuz ki, katmanlı mimaride tek bir değişiklik için farklı klasörlere temas etmek gerekmektedir. Vertical Slice’da ise tek feature için o özellikle ilgili tek bir klasöre odaklanmak yeterlidir. Haliyle bu açıdan bakıldığında dağınıklık ve context switching açısından oldukça avantaj yaratmaktadır. Ayrıca, Onion ve geleneksel mimaride yapılar zamanla interface’ler kullanılarak aşırı soyutlamalardan kaynaklı istemsizce şişmekte ve bu da kodsal yönetimi bir yerden sonra ciddi manada darboğaza sürüklemektedir. Vertical Slice’da ise gereksiz soyutlamalar reddedilmekte ve sadece ihtiyaç durumlarında teknik olarak değerlendirilmektedirler. Ee bu durumda dependency yönetimi açısından da sisteme ekstradan bir kolaylık sunmaktadır. Bunların dışında test edilebilirlik ve deploy süreçlerinde Vertical Slice oldukça avantaj sağlamakta, yeni biri ekibe geldiği taktirde de sade ve sadece ilgili slice ile muhattabı sağlanarak sürece adaptasyonu daha hızlı gerçekleştirilebilmektedir.

Vertical Slice’ın en güzel getirilerinden biri de hızlı prototipleme ile birlikte modüler genişlemeye uygun olmasıdır. Bu da yeni özellik geliştirilmesi gerektiğinde hızlı bir şekilde hareket edilmesini sağlamaktadır.

Geleneksel katmanlı mimari ile Onion Architecture gibi modern tasarımlar çeşitli bileşenlerdeki endişeleri ayırmaya (separating the concerns) odaklanmaktadır. Bu uğraş, yazılım sisteminin anlaşılması ve sürdürülmesi açısından elbet kolaylaştırıcı etkiye ve bir yandan da esnek ve gevşek bağ (loose coupling) gibi birçok faydalı getiriye sahiptir. Ancak katmanlı mimariler aynı zamanda sistemde ciddi kısıtlamalara ve katı kurallara sebebiyet verebilmektedirler. Özellikle katmanlar arasındaki bağımlılıkların yönü önceden net bir şekilde belirlendiği için yeni bir işlev eklemek veya mevcut bir özelliği değiştirmek çoğu zaman bu bağımlılık yönüyle doğru orantılı restorasyon dalgası oluşturmaktadır. Tabi bu söylenenlerden yola çıkarak katmanlı mimarilerin kötü olduğunu iddia edemeyiz! Vertical Slice Architecture ise bu mimarilere karşın yalnızca farklı bir yaklaşım sunmakta ve bahsi geçen belirli problem durumlarını düzeltebilecek daha uygun ortamlar yaratmaktadır.

Evet, katmanlı mimarilerde bir özelliği uygulayabilmek için birçok farklı katmanda değişiklik yapılması zaruridir. Vertical Slice Architecture ise farklı bir yaklaşım benimsemekte ve dilimler arasındaki bağımlılığı en aza, bir dilim içerisindeki bağımlılığı ise en üst düzeye çıkarmaktadır. Bu durumda, farklı bileşenler veya modüller arasında olabildiğince az bağımlılık olsun ki sistem esnek ve yönetilebilir kalsın, ancak her bir modülün kendi içindeki bileşenler arasında da güçlü bir bütünlük ve yakın işbirliği bulunsun minvalinde bir niyet söz konusudur diyebiliriz. Böylece her bileşenin kendi içinde atomik bir yeterliliğe ve mükemmelliğe sahip olması beklenecektir.

Son olarak, yatay mimarilerde dosyalar teknik sorumluluklarına göre Controllers, Services, Repositories vs. şeklinde ayrılmaktadırlar. Böylece bir iş/işlev/operasyon için gerekli çalışma 3-4 farklı klasöre dağılmaktadır ve bu durum da takibi zorlaştırmaktadır. Vertical Slice’da ise her bir kullanım senaryosu (use case) için özel bir küçük dünya tasarlanır ve gerekli Controller, Services, Repositories, DTO, Validators vs. dosyalarının hepsi bu dünya içinde oluşturulur. Böylece o kullanım senaryosu için fiziksel uyum (cohesion) oldukça yüksek olacaktır ve bu da geliştirme deneyimini basitleştirecektir. Ne de olsa her özelliğe ait tüm bileşenler birbirlerine yakın olduğu için geliştirici açısından ilgili dosyayı bulmak ve çalışmak kolaylaşacaktır.

Vertical Slice’ın Uygulanması

Vertical Slice’ın odağı özelliğe göre modülerleştirmektir…

Vertical Slice yaklaşımında her özellik (feature) için gerekli tüm bileşenler tek bir pakette/dosya grubunda bulunur.

Misal olarak; bir ‘Sipariş Oluşturma’ özelliği için

  • Controller / Endpoint
  • Request / DTO
  • Validator
  • Handler
  • Repository ve Data Access

yapıları aynı ‘slice’ içerisinde yer alacaktır. Böylece yeni özellik geldiğinde o feature’a göre yalnızca kod eklenecek, mevut kodlar değiştirilmeyecek ve böylece de yan etkiler (side effects) konusunda endişelenmeye gerek kalmayacaktır.

Elbet Vertical Slice’ın kendince avantajları olduğu gibi getirisi olan istemsiz zorlukları da olacaktır. Bunlardan biri, bütün iş mantığının önemli bir bölümünün tek bir kullanım senaryosunun (use case) içine gömülmesidir. Böyle bir durumda okunması, sürdürülmesi, genişletilmesi zorlaşan yapı anlamına gelen code smell durumu söz konusu olabilir, ki özellikle o sınıf ya da modül çok fazla şey de yapmaya başlayarak bu durum kaçınılmaza yakın olacaktır. Ee bu durumu da düzeltebilmek ve önleyebilmek için sürekli refactoring yapılması ve bir kısım iş mantığını merkezi hale getirmek gerekecektir.

Şöyle ki; Vertical Slice yaklaşımında her feature kendi bağımsız dünyasını kurduğu için, benzer iş mantıkları veya ortak DTO’lar farklı slice’larda tekrar tekrar (duplication) yazılabilir. Örneğin, ‘OrderDto’ veya ‘UserInfo’ gibi yapılar hem ‘CreateOrder’ hem de ‘GetOrders’ slice’ında yeniden tanımlanabilir. Bu durum klasik ‘kod tekrarı’ gibi görünse de, aslında dilim felsefesine göre bir kabul edilebilir trade-off durumu olarak değerlendirilebilir. Çünkü bu yaklaşımda bağımsızlık, tekrarın önüne geçmektedir.

Özetle; Vertical Slice iyi ve verimli bir yaklaşım olabilir amma velakin dikkat edilmediği taktirde use case’lerin God Object gibi şişebilme ihtimali de yok değildir.

Vertical Slice’ın REPR Pattern İle Benzerliği

Vertical Slice yaklaşımı REPR (Request-Endpoint-Response) pattern’i ile gayet başarılı uygulanabilecek şekilde bir uyuma sahiptir. Çünkü REPR pattern’ında Vertical Slice ilkelerine uygun şekilde, her dilim kendi içerisinde Request/Endpoint/Response üçlüsünü içermekte ve endpoint ise yalnızca orkestrasyon gerçekleştirmektedir.

Örnek Çalışma

Şimdi basit bir örnek üzerinden Vertical Slice yaklaşımını pratik düzlemde değerlendirmeye çalışalım.

public static class CreateProduct
{
    public record Request(string Name, decimal Price);
    public record Response(int Id, string Name, decimal Price);

    public class Endpoint
    {
        public void MapEndpoint(IEndpointRouteBuilder endpointRouteBuilder)
        {
            endpointRouteBuilder.MapPost("/products", (Request request) =>
            {
                Product product = new Product(1, request.Name, request.Price);
                //...
                //Create product...
                //...
                return Results.Ok(new Response(product.Id, product.Name, product.Price));
            });
        }
    }
}
public record Product(int Id, string Name, decimal Price);

Yukarıdaki çalışmada Vertical Slice Architecture yaklaşımının küçük bir numunesini göreceksiniz. Dikkat ederseniz yapılacak işlevle ilgili tüm özellikler CreateProduct class’ı içerisinde sıkı bir şekilde gruplandırılmıştır ve bu sayede, bu işlevle ilgili her şeyi bulmak, anlamak ve değiştirmek son derece kolay olacaktır ve birden fazla katmanda (controller, services vs.) gezinilmesine gerek kalmayacaktır. Tabi sizler bu mantığı alıp klasör seviyesine genelleyebilirsiniz.

Hoca la, misal olarak bu yaklaşımda validation’ları nasıl yapılandırabiliriz? sorunuzu duyar gibiyim… Hemen cevaplarsak eğer;

public static class CreateProduct
{
    .
    .
    .
    public class Validator : AbstractValidator<Request>
    {
        public Validator()
        {
            RuleFor(p => p.Name).NotEmpty().MaximumLength(100);
            RuleFor(p => p.Price).GreaterThanOrEqualTo(0);
        }
    }

    public class Endpoint
    {
        public void MapEndpoint(IEndpointRouteBuilder endpointRouteBuilder)
        {
            endpointRouteBuilder.MapPost("/products", async (Request request, IValidator<Request> validator) =>
            {
                .
                .
                .

                ValidationResult? validationResult = await validator.ValidateAsync(request);
                if (!validationResult.IsValid)
                    return Results.ValidationProblem(validationResult.ToDictionary());
                .
                .
                .
                return Results.Ok(new Response(product.Id, product.Name, product.Price));
            });
        }
    }
}

şeklinde izahta bulunabiliriz. Dikkat ederseniz her şey rahatlıkla ilgili işlevin grubuna eklenebilmekte ve hızlı bir şekilde çalışma sergilenebilmektedir. Ha tabi istendiği taktirde 19. satırda olduğu gibi endpoint’ler de dependency injection’dan da istifade edilebilmekte ve çalışmalar esasında bilinen klasik pattern’lar eşliğinde yürütülebilmektedir.

Tabi burada şu soruda akıllara gelebilir: Gerçek uygulamalara genellikle karmaşık etkileşimler, paylaşılan iş mantıkları (shared logic) ve süreçleri hakimdir. Bu açıdan bakıldığında Vertical Slice yaklaşımı ile gerçek bir zeminde çalışmak mümkün mü?
Evet, Vertical Slice yaklaşımı temelde kendi kendine yeten özellikleri yönetmede mükemmel bir altyapı sağlayabilmektedir. Ancak, her isteme karşın uygulanabilecek bir yaklaşım olmadığını da söylemekte fayda vardır. Misal test süreçleri açısından, her ne kadar dikey dilimler kendi içlerinde tutarlı olmasından kaynaklı unit ve integration testleri kolaylıkla uygulayabileceğimiz bir zemin sağlıyor olsa da, yukarıda bahsedildiği üzere paylaşılan iş mantıkları gerektiren senaryolarda ister istemez dezavantajlarıyla karşılaşılabiliyor. Bu farkındalıkla olayı değerlendirdiğimizde Vertical Slice yaklaşımını, kod organizasyonu ve geliştirme hızı açısından avantaj sağlayan bir alternatif olarak değerlendirebilir ve uygun projelerde deneyimleyerek, getirilerinden istifade edebilirsiniz.

Nihai olarak;
Bundan sonra Vertical Slice Architecture’ın faydalarını deneyimledikçe keşfedeceğimizi düşünüyorum. Ne de olsa, bu yaklaşımla geliştirilen uygulamalarda o anki odağınızın hangi dosya, hangi özellik demeden bozulmaksızın sürdürülebiliyor olması ve geliştirme sürecinde her şeyin birbiriyle uyum içinde akması biz geliştiriciler için oldukça tercih edilebilir bir süreç sağladığı aşikar olsa gerek. Ayrıca yine biz geliştiriciler açısından, geleneksel mimarilere nazaran bileşenlerin kendi içinde daha atomik bir yeterliliğe sahip olmasını sağlayarak daha az zihinsel enerji harcanmasını ve gerçek sorunların çözümü için daha fazla zaman kazanılmasını sağladığını da söyleyebiliriz.

İlgilenenlerin faydalanması dileğiyle…
Sonraki yazılarımda görüşmek üzere…
İyi çalışmalar…

Not : Örnek çalışmaya aşağıdaki GitHub adresinden erişebilirsiniz.
https://github.com/gncyyldz/Vertical_Slice_Architecture

Bunlar da hoşunuza gidebilir...

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir