Component Architecture : Cohesion & Coupling
COMPONENT ARCHITECTURE
Bir mimari tasarlarken hangi class hangi componentte yer alacağı önemli bir karar olup bize iyi ve kabul görmüş yazılım prensiplerinin rehberliğini gerektirir. Bunun için vakit harcamak bize kısa vadede zaman kaybettirecek olsa dahi uzun vadede çok kazandıracağı da aşikardır. Bu yazımda iyi tasarlanmış bir mimari kurgulamak için componentleri nasıl tasarlamalıyız? Hangi class hangi componentte yer almalı? Componentlerin birbirleriyle ilişkisi nasıl olmalı? gibi sorulara cevap getirebilecek prensiplerden kısa kısa bahsedeceğim.
Ancak öncelikle hepimizin bir noktada buluşup ortak bir dil üzerinden gidebilmesi için component kavramından ne anlamamız gerektiğini çok kısa açmak istiyorum. Componentler sistemin deploy edilebilecek en küçük parçalarıdır. Bu javada .jar , .Nette de .dll olarak geçer.
Component architecture için konuşacağımız prensipleri iki başlık altında toparlamak yerinde olacaktır. Biri cohesion diğeri ise coupling. Bu kavramları classlar için ele aldığımız gibi componentler için de ele alabiliriz.
1. COMPONENT COHESION
Cohesion kavramı class bazında da component bazında da ele alınabilen bir kavramdır. Cohesion, class ya da componentlerin birbirine ne kadar yapışık olduğunu ifade eder. Yapışıklığı da sınıf içerisindeki genel verilerin ortak kullanımı gibi düşünebiliriz. Örneğin sınıf içerisinde bulunan bir verinin, yalnızca tek bir metot tarafından kullanılırken, öbürlerinin bunun farkında bile olmaması yanlış bir tutumdur. Öte yandan her bir metodun yaptığı iş aynı amaca hizmet etmelidir. Yani konsept olarak da classın metotları ya da componentin classları birbirine yapışık olmalıdır. Yapılan işlerin alakasız olması yine yanlış bir tutum olarak görülür. İyi tasarlanmış bir class ya da componentin cohesionun yüksek olmasını(high cohesion) bekleriz. Component cohesion’u sağlayan prensiplerin ikisi CCP ve CRP’dir.
1.1 The Common Closure Prıncıple (CCP)
The Common Closure Principle (CCP)’nin söylediği şey, aynı amaç için değişebilecek classları aynı componentte tutmamız ve bir componentin değişmek için birden fazla sebebi olmaması gerektiğidir. Component bazında düşünüdüğümüzde Common closure Principle’ı uygulayarak aynı amaca hizmet eden classları aynı component altına alarak daha yapışık yani high cohesion’ı yüksek bir component elde ederiz. Bu sayede bir değişiklik ihtiyacı geldiğinde farklı componentlere dağılmış classlardan oluşan yani yapışkanlığı düşük (low cohesion) yapılara göre değişikliği yaptığımız component, deployment, revalidate sayısı düşecek ve iş yükü minimuma inecektir.
Aslında baktığımız zaman common closure principle’ın bize söylediğiyle single responsibility principle’ın bize söylediği aynıdır. Ancak Single responsibility bize bunu class bazında söylerken common closure principle bunu component bazında söyler. Yani aslında temelde bize söylenen şey tektir.
Aynı sebepten dolayı ve aynı anda değişebilecek şeyleri aynı yerde, farklı sebepler için farklı zamanlarda değişebilecek şeyleri farklı yerlerde tutun. Bir şeyin değişmek için birden fazla sebebi olmasın.
1.2 The Common Reuse Prıncıple (CRP)
The Common Reuse Principle da bize hangi classları hangi componentlere yerleştirmemiz gerektiğini söyleyen diğer bir prensiptir. Söylediği de, birlikte kullanılan class ve moduller aynı componentte olmalıdır. Yani böyle bir componentte çok fazla bağımılılık görmemiz gerekir.
The Common Reuse Principle bize bir componente bağımlı olan kullanıcıları, component içerisinde kullanmadıkları classlara bağımlı kılmamamızı söyler. Daha da detaylandıracak olursak, bir component diğer componenti kullandığında bu iki component arasında bağımlılık oluşur. Ancak component kullandığı diğer componentin yalnızca tek bir classını kullanıyor olsa bile bağımlılık yoktur yahut bağımlılık zayıftır diyemeyiz. İdealde bir component diğer componente bağımlıysa o componentin tüm classlarını doğrudan ya da dolaylı olarak kullanmalıdır. Aksi takdirde kullanılmayan classların logical olarak gerçekten o componente ait olup olmadığı değerlendirilip aynı bir componente taşınmalıdır.
paket X ve paket Y arasındaki bağımlılık yer almaktadır. Sınıf A paket Y’de bulunan B sınıfını kullanmaktadır. B sınıfı aynı paket içindeki C sınıfını kullanmaktadır. Bu durumda X paketinde bulunan A sınıfı dolaylı olarak Y paketinde bulunan C sınıfına bağımlı hale gelmektedir. C sınıfı üzerinde yapılan her değişiklik A sınıfını doğrudan etkileyecektir. B ve C sınıfları beraberce kullanıldıkları için aynı paket içinde yer almaları gerekir. CRP aynı zaman hangi sınıfların paket içine konmaması gerektiğine de açıklık getirir. Birbirine bağımlılıkları olmayan, birbirini kullanmayan sınıfların aynı paket içinde olmaları sakıncalıdır. Örneğin resim 7.12 da yer alan Y paketi içindeki D sınıfı, Y paketinde bulunan hiçbir sınıf tarafından kullanılmamaktadır. Bu durumda D sınıfının Y paketinde olmaması gerekir. Eğer D sınıfı değişikliğe uğrar ve Y paketinin yeni bir sürümü (release) oluşursa, bu aslında D sınıfı ile hiçbir ilgisi olmayan X paketindeki A sınıfını etkileyecektir, çünkü Y paketinin yeni sürümü X paketinin ve dolaylı olarak A sınıfının tekrar gözden geçirilmesini zorunlu kılacaktır.
Yani aslında temelde bize söylenen şey
Kullanmayacağın bir şeye bağımlı olma.
1.3 Sonuç olarak…
Bahsettiğimiz iki prensip Common closure ve Common reuse prensibi bize birbirleriyle aynı amaca hizmet eden ve birlikte kullanılan classları componentlere nasıl yerleştireceğimizi ve tersi durumlarda ise nasıl ayrıştıracağımızı anlatan prensiplerdir. Bu iki prensipler kendi içinde anlam bütünlüğü olan ve tekrar kullanılabilen classlardan cohesion’u yüksek componentler oluşturmayı amaçlayan prensiplerdir ve bakıldığında tek bir componentin içerisindeki classların kurgusu hakkında fikir sunar. Yani tek bir component kendi içinde cohesionu yüksek midir ya da değil midir değerlendirmesini yapmamızı sağlar. Farklı componentlerin birbiriyle ilişkisi içinse kaldığımız yerden devam edelim.. 🙂
2. COMPONENT COUPLING
Coupling kavramı sınıflar için ele alındığında birden fazla sınıf arasındaki ilişkiyi componentler için ele alındığında da birden fazla component arasındaki ilişkiyi temsil eder. Dikkate aldığı konu da şudur. Birbiriyle ilişkili varlıklar (class ya da component) birbirlerine sıkı sıkıya mı bağlı? (Tightly coupling) yoksa aralarında gevşek bir bağ mı var?(loosely coupling). Eğer bir class ilişkili olduğu başka bir class olmadan ele alınamıyorsa bu class bağlı olduğu classa sıkı sıkıya bağlıdır(Tightly coupling) ki bu istenmeyen bir durumdur. Tasarımlarımızı olabildiğince gevşek bağlı (loosely coupled) olarak inşa etmemiz beklenir. Classlar için coupling kavramını daha da detaylı incelemek istiyorsanız konuya aşağıdaki yazım ile devam edebilirsiniz. Zira yazının bu kısımda componentler arası coupling üzerinde duracağız.
Tightly coupled-Loosely coupled Sistemler ve Dependency Injection
2.1 The Stable Dependencıes Prıncıple
Mimari tasarımların tamamen statik olması beklenemez. Proje maintain edildiği sürece bazı componentler değişime uğraması bazılarının da durağan kalması gerekir. Stable Dependency Principle’ın bize söylediği, sistem tasarlarken statik componentler ile codebase’i sıkça değişen componentler arasındaki bağımlılıkların nasıl tasarlanacağıdır.
Static Dependency Prensibinin bize söylediği, “Sıkça değişecek compenetleri(unstable), nadiren değişecek componentlere(stable) bağımlı kılmalıyız”dır. Çok fazla componentin bağımlı olduğu main componentleri olabildiğince stable olarak tasarlamalıyız. Componentlerin bağlı olduğu temel componentler stable değilse, bu componentteki her bir değişiklik zincir şekilde bu componente bağımlı componentlerde de etki ve efor yaratacaktır. Bir diğer ifadeyle, bağımlılıkların yönü stable tarafa olmalıdır.
Stable depencedies ile ilgili daha detaylı bir yazıyı önceden yazmıştım detayları için aşağıdaki yazıya geçiş yapabilirsiniz.
Stable Dependencies Principle
2.2. The Stable Abstactıon Prıncıple
Stable dependency prensibinde bahsettiğim çokça değişecek olan unstable componentleri bağımlı kıldığımız ana temel componentleri stable olarak tasarlar ve çok az değişime uğramasını bekleriz. Zira bu componentlerde oluşacak her değişiklik zincir şeklinde bu componente bağımlı componentleri de etkilyecektir. Hızlı ve kolayca değişmesini beklediğimiz classları da yine yukarıda bahsettiğimiz gibi unstable bir component altında ayrıştırırız. Ancak, componentlerin stabil olmaları sisteme yeni davranış biçimlerinin kazandırılmasının önünde bir engel olmamalıdır. Peki tamamen stable tasarlanmış bir componente yeni özellik eklenmesi gerektiği durumlarda kırılgan olmaması ve esnek olması için nasıl bir yol izlemeliyiz? işte bunu da stable abstraction principle ele alır. Aslında SAP bize bunun çözümü için çok önceden bildiğimiz ve class bazında uyguladığımız prensibi component bazında da uygulamamızı söyler. Nedir bu? Open Closure Prensibi yani yapı değişikliğe kapalı ancak genişlemeye açık tasarlanmış olmalıdır.
Sap’a göre stable componentler genişlemeye açık olacak şekilde abstract tasarlanmalı. Konuyu biraz daha somutlaştırmak gerekirse, stable componentler genişlemeye fırsat verecek şekilde interface ve abstractlardan oluşmalıdır. Genişleyen componentler esnektir ve mimariyi kısıtlamaz.
2.3. Sonuç olarak…
Stable depencency principle ve stable abstraction principle cohesion prensiplerinden farklı olarak birden fazla componentin bağımlıklıkları ve tasarımı hakkında fikir sunar. Ve de iyi tasarlanmış bir mimari kurguda high cohesion – low coupling olmasını beklenir.