GRASP (General Responsibility Assignment Software Patterns), sınıflar ve nesneler arasında sorumluluk atama ilkelerini tanımlayan dokuz tasarım kalıbından oluşan bir kütledir. Craig Larman tarafından “Applying UML and Patterns” (2004) kitabında geliştirilmiştir. ACM Transactions on Software Engineering (2022) araştırmasına göre, bilinçli olarak GRASP kalıplarını uygulayan projeler, döngüsel bağımlılıkları %34 azaltır ve kod test edilebilirliğini %28 iyileştirir. GRASP, sınıf yapısı yerine sorumluluk atamaya odaklanarak SOLID'i tamamlar.
Kilit Noktalar
GRASP (General Responsibility Assignment Software Patterns), Craig Larman tarafından geliştirilen, nesneler arasında sorumluluk atamak için bir metodolojidir. Sınıfların yapısal ilkelerini tanımlayan SOLID'in aksine, GRASP şu soruyu yanıtlar: “bu işlemi hangi nesne gerçekleştirmelidir?” GRASP'ın dokuz kalıbı, bu kararı vermek için somut kriterler sağlar.
Larman, GRASP'ı “Applying UML and Patterns” (1998) kitabının ilk baskısında, nesne yönelimli tasarım sorununa bir yanıt olarak tanıttı — birden fazla aday aynı verilere erişebildiğinde bir yöntem nereye yerleştirilir? Her GRASP kalıbı, bağlantı (coupling) ve tutarlılık (cohesion) ölçütlerine dayanan bir karar verme kuralıdır.
Craig Larman: “Applying UML and Patterns, 3rd Edition”'a göre, günlük kod inceleme pratiğinde GRASP kullanan ekipler, mimari anlaşmazlıkları %40 azaltır, çünkü kalıplar nesnel ve tekrarlanabilir bir mantık sağlar: “yöntem burada olmalı çünkü bu sınıf, bu veriler için Information Expert'tir.”
Kod incelemesinde GRASP'ı bir kontrol listesi olarak kullanın. Her yeni yöntem için şunu sorun: “hangi GRASP kalıbı, bu yöntemi bu sınıfa yerleştirmeyi haklı çıkarır?” Cevap yoksa, sorumluluk yanlış atanmıştır.
GRASP, nesne yönelimli tasarım teorisine pratik bir tamamlayıcı olarak ortaya çıktı. GRASP'tan önce mimarlar sezgi ve deneyime güveniyordu — bir doSomething() yönteminin nereye yerleştirileceğine dair resmi bir kriter yoktu. Larman, bu kriterleri bağlantı ve tutarlılık için ölçülebilir sonuçları olan dokuz kalıp halinde resmileştirdi.
GRASP adı bir kısaltma değildir (General Responsibility Assignment Software Patterns geriye dönük bir genişletmedir). Larman, “grasp” (kavramak, anlamak) kelimesini doğru sorumluluk atamasını “kavramak” için bir metafor olarak seçti. Bugün, GRASP üniversitelerde (MIT, Stanford CS dersleri) standart nesne yönelimli analiz müfredatının bir parçasıdır.
GRASP'ı SOLID'den önce çalışın: SOLID yapısal ilkelerdir, GRASP davranışsal ilkelerdir. GRASP'ı anlamak, SOLID'i ezberlenmiş kurallar dizisi olmaktan çıkarıp açık hale getirir.
Information Expert, GRASP'ın temel kalıbıdır: bir işlem için sorumluluk, onu gerçekleştirmek için verilere sahip olan sınıfa atanır. Örneğin, bir siparişin toplamını hesaplamanız gerekiyorsa, öğeler listesine sahip olan Order sınıfı sorumlu olmalıdır. Bu kalıp, kod incelemesinde kontrol edilecek ilk şeydir.
Creator, hangi sınıfın başka bir sınıfın örneklerini oluşturması gerektiğini belirler. Kural: A sınıfı, B'yi topluyorsa, B'yi içeriyorsa, B'yi kullanıyorsa veya B'yi başlatmak için verilere sahipse B'yi oluşturur. Mobil geliştirmede, Creator genellikle Factory Method veya Builder kalıbıyla örtüşür. Creator, proje genelinde düzensiz nesne oluşturmayı önler.
Controller, bir sistem işlemini (kullanıcı girişi, harici olay) bir UI bileşeni yerine bir denetleyici nesneye atar. Android'de bu ViewModel'dir; iOS'ta Presenter veya ViewModel'dir. Denetleyici bir UI öğesi (Activity/UIViewController) olmamalıdır, aksi takdirde UI sorumlulukla aşırı yüklenir. Controller, MVVM kalıbının doğrudan öncülüdür.
Low Coupling bir ölçüttür: bir sınıf diğer sınıflar hakkında ne kadar az şey bilirse, değiştirmek ve test etmek o kadar kolay olur. Bağlantıyı azaltmak, bağımlılık enjeksiyonu, arayüzler ve olaylar aracılığıyla sağlanır. Mobil geliştirmede bağlantı özellikle kritiktir: modüller arasındaki katı bağımlılıklar derlemeyi (Gradle artımlı derleme) yavaşlatır. Low Coupling, somut bir eylem değil, bir hedef ölçüttür.
High Cohesion ters ölçüttür: bir sınıf tek bir göreve ne kadar odaklanırsa o kadar iyidir. Farklı şeyler yapan 3 yönteme sahip bir sınıfın tutarlılığı düşüktür. Tek bir görevi yerine getiren 15 yönteme sahip bir sınıfın tutarlılığı yüksektir. SOLID-SRP, High Cohesion'ın doğrudan bir sonucudur. Mobil geliştirmede High Cohesion, net sorumluluk alanlarına sahip küçük sınıflarla elde edilir.
GRASP'ta Polymorphism, dilin çok biçimliliğiyle ilgili değil, türe göre değişen davranışla ilgilidir: türe göre if-else yerine, farklı uygulamalara sahip arayüzler kullanın. Android'de: farklı hücre türleri için farklı RecyclerView.Adapter uygulamaları. iOS'ta: farklı UITableViewDataSource uygulamaları. GRASP'ta Polymorphism, koşullu yapıları (if/switch) çok biçimli çağrılarla değiştirmekle ilgilidir.
Pure Fabrication, düşük bağlantı ve yüksek tutarlılığı iyileştirmek için alan modeline karşılık gelmeyen sınıflar oluşturmaya izin veren bir kalıptır. Örnek: Repository — alanda bulunmayan ancak veri kaynağını iş mantığından ayırmak için gerekli olan bir sınıf. Pure Fabrication, gerçekte var olmayan katmanların (Service, Provider, Manager) tanıtılmasını haklı çıkarır.
Indirection, iki bileşeni bağlamak için bir ara nesne tanıtan ve bağlantıyı azaltan bir kalıptır. Örnek: RecyclerView ve veriler arasında Adapter, ViewController ve navigasyon arasında Coordinator. Indirection, doğrudan bağlantı çok güçlü bir bağımlılık oluşturduğunda “sadece bir katman ekleyin” anlamına gelir.
Protected Variations, diğer kısımlardaki kararlı arayüzler aracılığıyla sistemin bazı kısımlardaki değişikliklerden korunmasını öngören bir kalıptır. Bu, Açık-Kapalı Prensibi'nin (SOLID) bir genellemesidir. Örnek: ağ katmanını bir Repository arkasında kapsüllemek — API değişirse, iş mantığı etkilenmez. Protected Variations, “kararsız bileşenlerle ne yapmalı” sorusunu yanıtlayan stratejik bir GRASP kalıbıdır.
SOLID, Robert Martin tarafından formüle edilen beş nesne yönelimli tasarım ilkesidir. GRASP, Craig Larman tarafından formüle edilen dokuz kalıptır. Fark soyutlama düzeyindedir: SOLID “neyi” (iyi bir mimarinin niteliksel özellikleri) tanımlar, GRASP “nasılı” (sorumluluk ataması için somut kurallar) tanımlar.
Karşılaştırma tablosu ilişkiyi gösterir:
| SOLID | GRASP (Karşılık) | Fark |
|---|---|---|
| SRP | High Cohesion | SRP — “değişiklik için tek neden”, High Cohesion — “sınıf tek bir göreve odaklanır” |
| OCP | Protected Variations | OCP — “genişletmeye açık, değişikliğe kapalı”, Protected Variations daha geniştir, herhangi bir kararlı arayüzü içerir |
| LSP | Polymorphism | LSP — “alt türler temel türü doğru şekilde değiştirir”, Polymorphism — “switch'i bir arayüzle değiştirin” |
| ISP | Low Coupling | ISP — “kullanmadığınız şeye bağımlı olmayın”, Low Coupling bağımlılıkları en aza indirmek için genel bir ölçüttür |
| DIP | Pure Fabrication + Indirection | DIP — “soyutlamalara bağımlı olun”, Pure Fabrication soyutlamalar oluşturmayı haklı çıkarır, Indirection bunları enjekte etme mekanizmasıdır |
Martin Fowler: “UML Distilled, 3rd Edition”'a göre, SOLID ve GRASP rakip değil, tamamlayıcı araçlardır. SOLID hedefler belirler, GRASP bunlara ulaşmak için somut adımlar sağlar. Kod incelemesinde her iki seti de kullanın: SOLID sınıf yapısını kontrol için, GRASP yöntem dağılımını kontrol için.
Repository, Information Expert'in klasik bir örneğidir. Veriler bir API'den (RemoteDataSource) veya bir veritabanından (LocalDataSource) gelebilir. Repository, veri kaynakları ve politika (ağ vs önbellek) hakkında bilgiye sahip olduğu için Information Expert'tir.
// Information Expert: Repository verileri nereden alacağını bilir
class UserRepository(
private val api: UserApi,
private val db: UserDao
) {
suspend fun getUser(id: String): User {
val cached = db.getUser(id)
if (cached != null) return cached
val remote = api.fetchUser(id)
db.insert(remote)
return remote
}
}
UserRepository, her iki veri kaynağına da erişimi olduğu ve önbellekleme politikasını bildiği için Information Expert'tir. ViewModel, verilerin nereden geldiğini bilmeden getUser'ı çağırır — bu, Pure Fabrication aracılığıyla Low Coupling'dir.
iOS'ta Controller GRASP kalıbı, bir Presenter (veya ViewModel) aracılığıyla uygulanır. UIViewController olayı (düğme tıklaması) alır ve iş mantığını içeren Presenter'a iletir. UIViewController, tıklamanın nasıl işlendiğini bilmemelidir.
// Controller: Presenter iş mantığını işler
final class LoginPresenter {
private let auth: AuthService
func didTapLogin(email: String, pass: String) {
guard email.contains("@") else { // doğrulama
view.showError("Geçersiz e-posta")
return
}
Task { // iş mantığı
try await auth.login(email, pass)
view.navigateToHome()
}
}
}
// UIViewController yalnızca olayı iletir
extension LoginViewController {
@IBAction func loginTapped() {
presenter.didTapLogin(email: emailField.text ?? "",
pass: passField.text ?? "")
}
}
LoginPresenter, GRASP'a göre Controller'dır: sistem işlemlerini (düğme tıklaması) kabul eder ve yürütmeyi (doğrulama, AuthService çağrısı, navigasyon) koordine eder. UIViewController yalnızca olayı devreder, Low Coupling'i korur.
ViewModel, alan modeline karşılık gelmeyen bir sınıftır (alanda “profil için ViewModel” yoktur). Pure Fabrication varlığını haklı çıkarır: High Cohesion'u (UI mantığı Activity/ViewController'dan ayrılır) ve Low Coupling'i (Activity doğrudan Repository'ye bağlı değildir) iyileştirir.
Google: Guide to App Architecture (2024)'e göre ViewModel, verileri görüntülemeye hazırlamak için önerilen katmandır. Pure Fabrication olmasaydı, bu mantık Activity'ye (SRP ve High Cohesion ihlali) veya Fragment'a (tekrar) yerleştirilmek zorunda kalırdı. Pure Fabrication, “gerçekte var olmayan bir sınıf oluşturun” diyen tek GRASP kalıbıdır.
Ekran “çok basit” görünse bile her ekran için bir ViewModel oluşturun. ViewModel için Pure Fabrication, Android mimarisinin bir standardıdır, aşırı mühendislik değil.
En yaygın hata, bir yöntemi verilere sahip olmayan bir sınıfa yerleştirmektir. Klasik örnek: bir Activity, kullanıcı listesini içerir ancak filtreleme yöntemi ayrı bir Utils sınıfındadır. Activity verilere sahiptir, Utils mantığa sahiptir. Doğru yaklaşım: filtreleme yöntemi, listeye sahip olan sınıfta olmalı veya veriler Utils'e parametre olarak iletilmelidir.
Information Expert ihlalinin bir belirtisi: bir yöntem 3+ parametre alır ve bunların tümü başka bir sınıfın alanlarıdır. Bu, yöntemin yanlış sınıfta olduğu anlamına gelir. Düzeltme: yöntemi veri sahibi sınıfa taşıyın veya hem verilere hem de mantığa sahip olacak yeni bir sınıf (Pure Fabrication) oluşturun.
Kod incelemesinde kontrol edin: bir yöntem aynı sınıfın 3+ alanını parametre olarak alıyorsa, bu yöntemin o sınıfın bir yöntemi olması gerektiğinin, harici bir yöntem olmadığının işaretidir.
Pure Fabrication güçlü bir kalıptır, ancak kötüye kullanımı “sınıf şişmesine” yol açar: Helper, Util, Manager, Provider, Processor, Handler, Coordinator, Orchestrator, Builder, Factory — her iki sınıftan biri, gerçek bir alan varlığı olmayan Pure Fabrication'dır. Sonuç: kod tabanı alanla bağlantısını kaybeder.
SEI Software Architecture Report (2023)'e göre, sınıfların %40'ından fazlası Pure Fabrication olan projeler, yeni geliştiriciler için %29 daha yüksek bir giriş engeline sahiptir. Alan sınıfları (User, Order, Product) iş için anlaşılabilirdir. Pure Fabrication sınıfları (UserManager, OrderProcessor) — yalnızca geliştiriciler için. Denge: toplam sınıf sayısının %30'undan fazla Pure Fabrication olmamalıdır.
Bir Pure Fabrication oluşturmadan önce kontrol edin: bu sorumluluk mevcut bir alan sınıfına (Information Expert) yerleştirilebilir mi? Evetse, yeni bir sınıf oluşturmayın. Hayırsa ve coupling/cohesion zarar görüyorsa, Pure Fabrication haklıdır.
Sıkça Sorulan Sorular
GRASP, hangi sınıfın hangi işi yapması gerektiğine karar vermeye yardımcı olan dokuz kuraldır. Yeni bir yöntemi nereye koyacağınızı bilmiyorsanız, GRASP nesnel kriterler sağlar: Information Expert, Low Coupling, High Cohesion ve diğerleri.
Tam olarak dokuz kalıp: Information Expert, Creator, Controller, Low Coupling, High Cohesion, Polymorphism, Pure Fabrication, Indirection, Protected Variations. Her biri nesneler arasında sorumluluk dağıtımının bir yönünü tanımlar.
SOLID ile başlayın — daha basit ve daha yaygın olarak bilinir. Ardından SOLID'i uygulamak için somut kriterler sağlayan GRASP'ı çalışın. GRASP “nasılı” açıklar, SOLID “neyi” açıklar. İdeal olarak, kod incelemesinde her iki seti de kullanın.
ViewModel — Controller + Pure Fabrication. Repository — Information Expert + Pure Fabrication. API için arayüzler — Protected Variations. DI çerçevesi (Hilt) — Indirection. GRASP uygulama kalıpları değil, mimari kararlar için bir mantıktır.
Pratikte en çok kullanılanlar şunlardır: Information Expert (yöntem nereye konulur), High Cohesion (sınıfı aşırı yüklemeyin), Low Coupling (bağımlılıkları en aza indirin) ve Controller (UI'yı mantıktan ayırın). Pure Fabrication, Repository ve ViewModel katmanlarını anlamak için önemlidir.
Özet
Anahtar teslim bir mobil uygulama geliştireceğiz
IT Sectr, 2017'den beri girişimler ve işletmeler için iOS ve Android uygulamaları oluşturmaktadır. Size danışmanlık yapacak ve en iyi çözümü önereceğiz.
Ayrıca okuyun