Koray Kırdinli

Yazılım ve İş Yaşamı Hakkında Paylaşımlar

Kodlama Esnasında Dizayn – Code Complete C5

PART || – Yüksek Kalitede Kod Yazma

CHAPTER 5

KODLAMA ESNASINDA DİZAYN

5.1 Çoğu insan dizaynı kodlama aktivitesi olarak görmemekte , küçük projelerde bir çok aktivite gibi dizayn da bir kodlama aktivitesi olarak görülmekte ancak büyük projelerde dizayn kodlamadan önce yapılabilmekte.Küçük çaplı projelerde programcı klavyenin başındayken sınıflar ve interface ler tasarlar , sınıf diagramlarını çizer başka bir arkadaşına problemle ilgili kullanılablecek tasarım desenini sorar vs. Proje küçük olsa da tasarıma önem verilmelidir.

İYİ TASARIM : Tasarım isterlerin toplanmasından kodlama ve hata ayıklamaya kadar süregelir. Üst seviye dizaynı iyi olursa bu alt seviyedeki dizayna da yardımcı olur.İyi bir tasarım yapılmazsa kodun başka bir yerinde de kötü bir tasarıma yol açabilirsiniz ayrıca tasarımınızın ne kadar iyi olduğunu algılamak zordur aynı problem için birden fazla kabul edilebilir iyi dizayn yapılabilir.

İdeal olarak bütün sistem stabil olarak çalışabilmelidir , sıfır kaynak tüketmeli , sıfır bandwith tüketmeli , hata içermemeli , geliştirme maliyeti olmamalı Ancak gerçek dünyada tasarımcının görevi bu sayılanlardan optimumu yakalamaktır.

Tasarım durağan değildir zaman içinde değişebilir.

5.2 Anahtar Noktalar

– Kompleksliği Yönetmek

Yazılım geliştirmede iki tip zorluk bulunmakta.Bunlar rastlansal ve temel zorlunluluklar. Örneğin bir arabanın araba olabilmesi için motoru , tekerlekleri ve kapıları olmalıdır , eğer bu şartlar sağlanmazsa araba olamaz. Bu temel zorlunluluklar sınıfına girmektedir.Rastlansal zorlunluluklara da örnek olarak zorunlu olmayan örneğin ABS , 4 silindirli olma gibi özellikleri sayabiliriz, yani opsiyoneldir.

Proje başarısızlıklarının nedenleri genelde ; iyi planlanmamış , iyi yönetilmemiş , isterleri iyi toplanmamış olmasıdır. Bu başarısızlık teknik bir sebepten olabileceği gibi projenin kompleksliğinden de kaynaklanabilir.Komplekslik kesinlikle yönetilmesi gereken bir aktivitedir.
Bir problemin kompleksliğini azaltmak için küçük alt sistemlere bölmek gerekir.  İnsan beyni karmaşık bir yapıyı , parçalara ayrılmış bir yapıya göre daha zor  kavrar.
Kod yazarken , bir problemi çözerken önce istenilen işi yapmak gerekir daha sonra daha iyi bir çözüm olabilir mi diye üzerine yoğunlaşılmalıdır.

İyi dizayn için aşağıdaki kriterler sağlanmalıdır.

Minimum Karmaşıklık : Başkalarının da anlayabileceği şekilde bir dizayn yapılmalıdır.
Kolay Bakım : Bakım yapan programcıya anlaşılır bir kod sağlanmalıdır.
Loose Coupling : Programın iki parçası birbirine mininum bağımlılık içermelidir.
Genişleyebilir : Bir parçasında değişiklik diğer parçaları etkilememelidir. Temel sağlam olmalı üzerine inşa rahatça devam edilebilmeli.
Tekrar Kullanılabilirlik : Geliştirilen bir kod parçası diğer bir sistemde de kullanılabilmelidir.
High fan-in : Sistemin alt seviyelerdeki sınıfları kullanması
Low-to-medium fan-out : Bir sınıf az sayıda sınıfı (7den az) kullanmalı yoksa kompleksliği artar.
Portability : Bir sistemi kolayca başka bir ortama taşınabilmesi
Leanness : Dizaynı bozmadan bir parça çıkarıldığında veya eklendiğinde geriye uyumlu olabilmesi gerekir.
Stratification : Bir sınıfı anlamak için başka sınıflara bakmaya gerek kalmadan anlaşılabilmesi gerekir. Örneğin bir sürü eski  kodun kullanıldığı bir sisteme bir arayüz üzerinden erişim sağlamak.

Yazılım geliştirirken yapılması gereken adımlar:

Seviye 1: Öncelikle sınıf ve metodları tanımlamaya başlamadan önce sistemi bütün olarak ele almakta fayda vardır.

Seviye 2: Sistemi alt sistemlere ayrıştırmak. Bu parçalar büyük olabilir örneğin  veritabanı , kullanıcı arayüzü , raporlama aracı ve iş kuralları. Bu seviyede sistemi hangi alt sistemlere bölüneceğine ve diğer alt sistemlerle nasıl bir etkileşim içinde olacakları belirlenir. Bu etkileşim çok karmaşık olmamalıdır. Örneğin kullanıcı arayüzünü değiştirecek bir programcı diğer alt sistemleri de anlamak zorunda kalmamalıdır.

Seviye 3:Sınıfların ve birbirleri  ile olan etkileşimin belirlenmesi.

Seviye 4: Sınıfların metodlarının belirlenmesi.

Seviye 5: Metodların kodlarının yazılması.

5.3 Kod Bloglarının Dizayn Edilmesi.
Yazılımcı olarak bizler sorunun veya problemin bize net olarak gelmesini bekleriz , önce A yı sonra B yi yap gibi. Bu adımları teker teker geçtikten sonra sistem çalışmayınca sinirleniriz. Tasarım kod yazmadan farklı olarak sezgiseldir ve tek bir doğru cevabı yoktur.

– Örneğin Personal Time-Billing Sistemi geliştireceğiz. Sınıf diyagramı aşağıdaki gibi olsun.

Her bir nesnenin özellikleri vardır. Örneğin Employee nesnesinin özellikleri name,title,billingRate dir. Görsel kullanıcı arayüzünde butonlar, messageBoxlar, forlar,çizme araçları hepsi birer nesnedir.
– Herbir nesnede neler değişebileceğinin belirlenmesi

– Bir nesnenin diğer nesneler üzerinde yapacaklarının belirlenmesi.Hangi nesne hangi nesneleri içinde barındıracak,kim kimden kalıtım alacak,

– Bütün metod ve değişkenlerin public mi private mi olacağının belirlenmesi.
– Her nesneye bir arayüz uygulanması.

Nesneye dayalı bir tasarıma iki farklı yoldan gidilebilir. Birincisi üst seviyedeki sınıfların (interface,abstract) tasarımı ikincisi ise alt sınıfların tasarımı. İyi bir sınıf organizasyonu yapabilmek için öncelikle sistemin bütünü ele alınmalı ve genel üst seviye sınıfların yapısı çıkarılmalıdır. Daha sonra üst sınıflardan alt sınıfların detaylandırılması işlemi yapılmalıdır.

Abstraction : Soyutlama : Base sınıflar yapmak bir sınıfın detaylarına inmeden genel yapısı hakkında fikir edinmemizi sağlar. Soyutlamanın en büyük faydası gereksiz detaylardan bizi kurtarmasıdır.
İyi programcılar fonksiyon-interface seviyesinde,sınıf-interface seviyesinde ve package-interface seviyesinde soyutlama yapar.

Encapsulation : Kapsülleme : Soyutlamanın olmadığı bir yerde nesnenin herhangi bir özelliğini gizlemek için kullanılır.

Bir sınıf tasarlarken anahtar nokta sınıfın hangi özelliklerinin dışa açılacağının belirlenmesidir. Örnek olarak bir herhangi bir yere log tutan bir sınıfınız var ve kullanıcıya bu logları gösteriyorsunuz. Bu sınıfın dosyayı nereye yazdığı veya dosya uzantısının private olması gerekir çünkü veriyi geriye liste halinde alıyoruz. İyi bir sınıf tasarımı dışarıya mininmum karmaşıklık yansıtanıdır. Bunu bir buz dağının suyun altında kalan kısmına benzetebiliriz.

Örnek : Bir A sınıfının integer tipinde id isminde bir değişkeni var ve tekil olması gerekiyor. Bir de global düzeyde maksimum id yi tutan g_maxId değişkeni olsun. Her yeni nesne yaratılırken id = ++g_maxId; ile yeni bir id olması garanti ediliyor. Şimdi bir düşünelim burada ne tür sorular bizi bekleyebilir.

–          Belli bir Id aralığı olacak mı , Güvenlik için Id ‘yi birer birer değil de çoklu artırmak istersek ne olacak , Silinen id leri kullanmak istersek ne olacak.

Şimdi yukardaki gibi id’yi id = ++g_maxId; şeklinde verdiğimizde bir değişiklik yapmamız gerektiğinde yeni nesne oluşturduğumuz her yerde kodu değiştirmek zorunda kalırız. Bu bizim istediğimiz bir şey değil. Veya uygulamamız multi thread ise yukarda bahsedilen yapı çalışmaz. Id = NewId(); daha sağlıklı ve yönetimi kolay bir yapıyı bize sunar. NewID() rutini arka planda istenilen işleri yapar ve onları gizler.

*** A sınıfındaki bir metod B sınıfını çağırıyor ve B sınıfındaki bir metod A sınıfını çağırıyorsa bu hatalı bir yapıdır.
*** Bir Id yi integer tanımlamak yerine kendi oluşturacağınız bir IdType tipinden yaratın.

İyi bir tasarım yapmak için yazılım içerisinde sık değişebilecek yerleri tespit etmek gerekir. Değişmesi muhtemel parçaları birbirinden ayır ve diğerlerinden izole et. Çok değişen parçalar genelde iş kurallarıdır.
-Donanımdan Soyutlamak : Örneğin programınız yazıcı , ses aygıtları , iletişim araçları , sabit disk gibi donanımlar ile iletişim halinde ise donanım değişikliklerinde zarar görmemek için bu donanımları alt sisteminizden veya ilgili sınıfınızdan soyutlamanız gerekir. Taşınabilirlik açısından da önemli.

-Kullanıcı input ve outputundan sistemi soyutlamak : Örneğin bir dosya çıktısı veriyorsanız bunun uzantısını soyutlamalısınız. .xls , .xlsx , csv gibi
-Standart haline gelmemiş dil özelliklerini kullanmak sakıncalıdır.
-Bir durum değişkeni için boolean kullanmak sakıncalı onun yerine enumaration.

-Bir durum değişkenini direk kontrol etmek yerine bir alt rutinde kontrol etmekte fayda var.

Loose  Coupling : Sınıfların birbirleri arasındaki bağımlılıkları yok etmek.
Örneğin az parametreli fonksiyonlar çok parametrelilere göre daha az bağımlı olurlar ; Bir sınıfın çok fazla public metodu varsa bu da bağımlılığı artırır.
Modüllerin birbirleri arasındaki erişimi doğru yapılandırılmalıdır , örneğin bankacılık işlemlerinde bir modül yetkisi olmadığı başka bir modülü görememelidir. Esneklik ise bir değişikliğin yapılmasının ne kadar zor veya basit olduğu ile ilgilidir.

Bağımlılık çeşitleri :
Simple-data-parameter coupling : Datanın parametre olarak aktarıldığı kabul edilebilir bir bağımlılıktır.
Simple-object coupling :
Object-parameter coupling
Semantic coupling

Tasarım Desenleri : Sıkça karşılaşılan sorunlara genelleştirilmiş çözümlerdir.

5.4 Tasarım Pratikleri.

Bir program yazdığınızda aynı programı tekrar yazmak istediğiniz olmuştur. Bir kez yazdıktan sonra artık o programı daha iyi kavradığımızdan dolayı tasarımı konusunda daha iyi çözümler sunabilir. Tasarım iteratif bir olgudur. A noktasından B noktasına vardığınızda tekrardan A noktasına dönmek zorunda kalabilirsiniz.

Olaya üst seviyeden bakmak olayın alt seviye detaylarını persfektif olarak anlamamıza yardımcı olur. Bir dizayn iyi dörünüyorsa yeni teknikler uygulamamazlık yapmayın çünkü bir sonraki yapacağınız her zaman bir öncekinden iyi olacaktır.

Böl-Parçala-Yut : Hiçkimsenin beyni karmaşık bir programın tamamını içerecek kadar yeterli değildir.Karmaşıklık ile başa çıkabilmenin yolu onu daha küçük parçalara ayırmaktır.
Yukarı-Aşağı ve Aşağı-Yukarı Tasarım Yaklaşımları : İnsan beyni bir zamanda belli büyüklükteki bir detaya bir seferde konsantre olabilir. Eğer incelemeye sadece genel sınıflardan başlanırsa ilk başta çok fazla detaylarla uğraşmak zorunda kalınmaz. Genel sınıflar daha küçük sınıflara ayrıştırılır. Bu ayrıştırma işlemi sınıfları ve metodları en basit haline getirene kadar devam eder.
Bazen de tam tersi olarak sistemi bilmeden sadece alt seviyedeki bir modülü veya sınıfı geliştirmek gerekebilir. İki yöntemin de bir birine göre artı ve eksileri bulunmaktadır.

Deneysel Örnekleme: Bir tasarım yapıldığında bunun çalışıp çalışmadığını implementasyon yaparak daha iyi görebiliriz. Tasarımı çalıştırmak için mininmum kod yazılır.
İşbirlikçi Tasarım : Tasarımı bir başkası ile birlikte yorumlamak.
Kodlamaya Geçmeden Önce Ne Kadar Tasarım İle Uğraşmak Gerekir ? : Bu sorunun cevabı projenin kapsamı , takımın tecrübesi gibi kriterlere göre karar verilebilir

Use CRC (Class, Responsibility, Collaborator) cards
Create UML diagrams at appropriate levels of detail

January 12, 2010 - Posted by | Yazılım | , , , , ,

No comments yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s