Coupling ve Cohesion: Yazılımın Gizli Kahramanları!
Mesele hiçbir zaman ışıltılı mimariler olmadı. Tüm arzumuz bağımlılıkları doğru şekilde yönetmek!
Developer olarak kendimizin en iyi versiyonuna ulaşmak için çabalıyoruz. Bunun için genellikle popüler mimarilere veya framework’lere odaklanıyoruz. Örneğin, son yıllarda sıkça konuşulan ve oldukça popüler olan; Modular design, Clean Architecture, Domain-Driven Design, Hexagonal Architecture gibi yaklaşımlar. Ancak, tüm bu çabalara rağmen verdiğimiz tasarım kararları bizi çoğu zaman complexity cehenneminden çıkaramıyor.
Hatta, son yıllarda mikroservis mimarisinden modular monolith’lere yönelen geliştiricilerin sayısı arttı. Çünkü yazılım dünyası ne kadar analitik görünse de tamamen iyi veya tamamen kötü tasarım diye bir şey yoktur. Konu, daha çok artılar, eksiler ve içinde bulunduğumuz koşullara göre hangi eksileri tercih edeceğimiz ile ilgilidir.
Popüler mimarilerden o kadar çok bahsettik ki işin özündeki parametreleri kaçırır olduk. Biraz daha uzaktan baktığımızda, bir sistemden temel olarak üç beklentimiz olduğunu görebiliriz:
• Maintainability: Sisteme sürdürülebilir bir şekilde bakım yapılabilmesi.
• Scalability: Sistemin ihtiyaç duyulduğunda genişleyip küçülebilme yeteneği.
• Reliability: Sistemin güvenilir şekilde çalışması, yani bir etkiye karşı her zaman beklenen tepkiyi (response) vermesi.
Bu maddeler kesinlikle daha detaylandırılabilir, ancak kabaca, bunca çabamızın ardında bu üç yeteneğe sahip sistemler kurma arzusu yatar. Bir developer, kariyeri boyunca sistemler üzerinde bu yetenekleri inşa etmek ve korumak için uğraşacaktır diyebiliriz.
Peki Neyi Kaçırıyoruz?
Coupling ve beraberinde gelen cohesion. Peki benim bu konuya odağımı çevirmem nasıl oldu? Learning Domain-Driven Design kitabının yazarı Vlad Khononov geçtiğimiz aylarda yeni bir kitap yayımladı: Balancing Coupling in Software Design.
Geçtiğimiz ay, Khononov’un Tech Excellence youtube kanalında bu kitabından kesitler içeren bir sunumunu dinledim. Sunum sırasında, beyin kıvrımlarımın adeta titreştiğini hissettim 🤯 Bu kadar zorlanmam normal miydi? Evet, tamamen normaldi; çünkü coupling ve cohesion, yazılım sektöründeki en soyut ama bir o kadar da önemli kavramlardan biri.
Dahası, bir süredir bu konuları neredeyse hiç konuşmadığımızı fark ettim. İşte bu yüzden, niyetlendim ve bu kavramları en basit haliyle anlatmaya karar verdim!
Önce Sistemleri Tanıyalım
Coupling’i anlamak için öncelikle sistem kavramını tanımamız gerekir. Çünkü her sistem, kendi içinde bir coupling barındırır.
Eğer birden fazla bileşen bir araya geliyor, birbirleriyle etkileşim kuruyor ve bu süreç sonucunda belirli bir hedefe ulaşıyorsa, buna bir sistem diyebiliriz. Bu durumu şu şekilde formüle edebiliriz:
SYSTEM = Components + Interactions → Goals
Örneğin, kolunuzdaki saat bir sistemdir. Saatin içinde birçok çark (bileşen) bulunur. Bu çarklar hareket ederek (etkileşim) saatin çalışmasını sağlar ve zamanı göstermesi hedefini yerine getirir.
Bünyesinde çalıştığınız şirketler de birer sistemdir. Hatta bu şirketler, kendi içinde birçok alt sistem barındırır.
Şirketi Bir Sistem Olarak Ele Alalım
Bir şirketin tamamını bir sistem olarak düşünebiliriz. Bu sistemin bileşenleri, etkileşimleri ve hedefi şu şekilde tanımlanabilir:
Bileşenler (Components):
• Teknoloji departmanı
• İnsan Kaynakları (IK) departmanı
• Satış departmanı
Etkileşimler (Interactions):
• IK departmanı, teknoloji departmanı için işe alımları gerçekleştirir.
• Teknoloji departmanı, satış departmanı için çalışan yazılımlar üretir.
• Satış departmanı, teknoloji departmanının ürettiği ürünleri son müşteriye ulaştırır.
Hedef (Goal):
• Yüksek satış yapan ve kar eden bir şirket oluşturmak.
Bununla birlikte, her bir departman da kendi içinde birer sistemdir. Örneğin:
• Teknoloji departmanı: Yazılım geliştirme süreçleri, kodlama standartları, ve ekip içi iş akışlarıyla kendi içinde çalışan bir sistemdir.
• IK departmanı: İşe alım süreçleri, çalışan memnuniyeti, ve performans değerlendirme gibi kendi süreçlerini yürütür.
• Satış departmanı: Müşteri ilişkileri, pazarlama stratejileri ve satış hedefleri gibi alanlarda bağımsız bir şekilde çalışır.
Burada önemli olan, departmanlar birbirinden soyutlanmış olsa da şirket hedefine ulaşmak için hepsinin birlikte çalışmasının gerektiğidir. Örneğin, satış departmanı çalışmasa da teknoloji departmanı işleyişine devam edebilir. Ancak, şirketin genel hedefi olan yüksek satış ve kar elde etme amacı için her iki departmanın da aktif ve etkili bir şekilde çalışması zorunludur.
Etrafımız, sayısız sistemle dolu ve bu sistemlerin sağlıklı bir şekilde çalışmasına ihtiyacımız var. Bunun için her sistemin otonom bir şekilde çalışması, yani hem kendi içinde hem de diğer sistemlerle düşük coupling seviyesinde olması gerekiyor. Aynı zamanda her sistem bileşeninin sadece kendi görevini yerine getirmesi ve kendiyle aynı veya benzer işi yapan diğer bileşenlerle yakın bir ilişki içinde olması şart. Bu da sistemlerin high cohesion ile çalışmasını gerektiriyor.
Bu bakış açısıyla düşündüğünüzde etrafınızda yüzlerce sistem görebilirsiniz: aile, devlet, insan vücudu, işletmeler…
Başarılı sistemlere yakından baktığınızda, genellikle loosely coupled ama aynı zamanda highly cohesive yapılar olduklarını fark edersiniz 🤓.
Coupling Her Yerde!
Coupling’e “bağlama”, cohesion’a da “yapışma” demeyeceğim, ne bu yazımda ne de başka bir yerde! Gereksiz Türkçeleştirmenin anlam düşüklüğüne neden olduğunu ve konuyu kavramayı çok daha zorlaştırdığını düşünüyorum.
Coupling her yerde, çünkü sistem olarak tanımladığımız her şey doğası gereği bir coupling barındırır.
Örneğin, insan vücudu. İskelet sistemi, sindirim sistemi gibi alt sistemlerden oluşur ve insan vücudu, bu alt sistemleri içinde barındıran bir üst sistemdir.
Dolaşım Sistemine Yakından Bakalım
Sistem Bileşenleri:
• Kan
• Damarlar
• Kalp
• Akciğerler
Etkileşimler:
• Kalp, kanı damarlar aracılığıyla pompalar.
• Kan, akciğerlerden oksijen alır ve karbondioksiti bırakır.
• Damarlar, kanı organlara taşır.
Hedefler:
• Oksijen ve besin maddelerini vücut hücrelerine ulaştırmak.
• Hücrelerden karbondioksit ve diğer atık ürünleri uzaklaştırmak.
• Vücut sıcaklığını düzenlemek.
Dolaşım sisteminde, her bir bileşen kendi görevini yerine getirir ve yalnızca bu göreve odaklanır. Üstelik birlikte hareket etmesi gereken bileşenler birbirine yakındır. Kalp ve akciğer, damarlar ve kan bu duruma iyi birer örnektir. Bu, sistemde high cohesion olduğunu gösterir.
Hedeflere ulaşmak için ise dolaşım sistemindeki bağımlılıklar optimize edilmiştir. Örneğin, akciğerlerde geçici bir sorun olduğunda damarlar ve kalp işlevini sürdürür; kan pompalama devam eder ve bu, üst sistemin (vücudun) genelinde bir sorun yaşanmasını engeller. Ancak kalp ile doğrudan bağlantılı bir damarda sorun olursa dolaşım sistemi işlevini yerine getiremez. Bu, sistemde gerekli bir coupling olduğuna işaret eder. Kalp ve damarlar birbirine tightly coupled (sıkı bağlı) çalışır.
Bir sistemde coupling’i tamamen ortadan kaldırmak mümkün değildir. Eğer kalp, damar ve akciğer arasında hiçbir bağlantı olmasaydı, dolaşım sisteminin hedeflerine ulaşmasını bekleyemezdik.
Coupling zorunludur ve sistemin sağlığı için optimize edilmelidir. İşte tüm çabamız, yazılım sistemlerinde de benzer bir seviye yakalamaya çalışmaktır. Dolaşım sistemini yazılımda çalıştığınız herhangi bir modüle çok rahatlıkla benzetebilirsiniz.
Bu soyut kavramı yeterince somutlaştırdıysak, şimdi yazılım dünyasındaki örneklerine geçebiliriz.
Sipariş Sistemi Üzerinden Coupling’e bakış
Örnek bir sistem olarak bir yemek sipariş sistemi düşünelim. Bu sistemde, sipariş sisteme düşer düşmez müşteriye bir bildirim (örneğin, SMS) göndermemiz gerektiğini varsayalım.
Tightly Coupled Sistem Örneği
Bu sistemde bir order service (sipariş servisi) bulunmaktadır. Servis şu adımları takip eder:
1. Siparişi yaratır.
2. Sipariş başarılı ise SMS gönderir.
3. SMS gönderme işlemi başarılı olursa client’a başarılı bir cevap döner.
Peki, SMS gönderme noktasında sistem bir hata ile karşılaşırsa ne olur? Burada birden fazla olumsuz senaryo oluşabilir.
Müşteriye başarısız cevap dönülür.
Eğer SMS gönderme işleminden önce siparişin yaratılma işlemi başarıyla tamamlandıysa (transaction sonlandıysa), bu durumda inconsistency (tutarsızlık) sorunu ortaya çıkar. Müşteriye başarısız bir cevap döneriz, ancak sistemde aslında bir sipariş yaratılmıştır. Bu siparişi birilerinin manuel olarak iptal etmesi gerekecek!
Üstelik bu sistemde sipariş yaratma akışı, SMS gönderme akışına sıkı sıkıya bağlıdır; yani sistem tightly coupled bir yapıdadır. Üstelik, OrderService’in görevi yalnızca sipariş yönetimiyle sınırlı olması gerekirken, aynı zamanda sipariş yaratıldıktan sonra SMS gönderilmesi gerektiğini de bilmektedir. Bu da OrderService’e gereksiz bir bilgi ve beraberinde fazladan bir sorumluluk yükler.
Peki, bu sistemi loosely coupled ve highly cohesive hale nasıl getirebiliriz?
Bu yeni tasarım kararlarıyla:
1. OrderService’in Cohesion’ını Artırdık:
Öncelikle, OrderService yalnızca kendi sorumluluğunu yerine getirecek şekilde yeniden tasarlandı. Artık sadece sipariş yönetiminden sorumlu ve başka bir işlevi üstlenmiyor. Bu sayede, cohesion artırıldı.
2. Broadcast ile Mesaj Yayını:
OrderService, başarılı bir sipariş oluşturma işleminin ardından bir broadcast ile mesaj yayınlıyor. Bu mesajı kimin alıp işlediğiyle ilgilenmiyor. Bu sayede, notification sistemine olan bağımlılığı (coupling) azaltılmış oldu.
3. Notification Gönderimini Queue ile Yönetmek:
Notification aksiyonu bir queue sistemi (örneğin RabbitMQ, Kafka) üzerinden yönetiliyor. Böylece bağımlılık tersine çevrildi: artık OrderService, notification aksiyonuna bağımlı değil; NotificationService ise message queue’ya bağımlı hale getirildi.
4. Notification Sistemini Daha Esnek Hale Getirdik:
Notification sistemi yalnızca SMS göndermekle sınırlı kalmadı; artık email ve push notification gibi farklı bildirim türlerini de destekleyecek şekilde tasarlandı. Bu sayede, sistemin esnekliği artırıldı.
Mikroservis Mi?
Bu yeni tasarım, bir mikroservis mimarisine benzeyebilir; ancak mikroservis değildir. Burada servisi bağımsız olarak deploy edilebilir hale getirmek tamamen farklı bir karardır. İhtiyaç varsa yapılabilir, ancak bu tasarımın bir zorunluluğu değildir.
Burada asıl yaptığımız şey, bağımlılıkları daha iyi yönetmek ve coupling’i abstraction kullanarak azaltmaktır. Yani mesele, süslü mimariler değil; sistemin bağımlılıklarını doğru şekilde yönetmektir.
Sonuç
Yazılım dünyasında coupling ve cohesion gibi soyut kavramlar, sistem tasarımının kalbinde yer alır. Bu kavramları anlamak ve uygulamak, sadece karmaşıklığı yönetmekle kalmaz, aynı zamanda sürdürülebilir, ölçeklenebilir ve güvenilir sistemler inşa etmenin temel taşlarını oluşturur.
Coupling, bir sistemin olmazsa olmazıdır; ancak optimize edilmediğinde karmaşık, kırılgan ve zor yönetilen yapılara yol açar. Cohesion ise bir modülün başarısını belirler; net sınırlarla ve odaklanmış görevlerle çalışan bir modül, sistemin genel verimliliğini artırır.
Bu makalede, hem gerçek hayattan hem de yazılım dünyasından örneklerle coupling ve cohesion kavramlarını somutlaştırmaya çalıştım. Dolaşım sisteminden sipariş sistemine kadar verdiğimiz örnekler, bu kavramların hayatın her alanında nasıl etkili olduğunu ve başarılı sistemlerin temelinde yattığını gösterdi.
Unutmayalım ki mesele, popüler mimariler veya süslü tasarımlar değil, hiçbir zaman da olmadı. Asıl mesele, bağımlılıkları doğru şekilde yönetmek, karmaşıklığı anlamak ve sistemin ihtiyaçlarına uygun çözümler üretebilmektir.
Bu kavramlara hakim olmak, bir geliştiriciyi sadece daha iyi bir yazılımcı yapmakla kalmaz, aynı zamanda iyi tasarlanmış sistemlerin mimarı haline getirir. Ve işte bu, yazılım geliştirme dünyasında fark yaratmanın en güçlü yollarından biridir.
Bukadar basit ama detayli ve anlasilir anlatilamazdi. Tebrikler cok guzel bir makale