Monthly Archives: August 2008

Spagetti Kod

spagetti1

Spagettiyi sevmeyenimiz yoktur dimi?Şöyle üzerinde de güzel bir sos oldumu tadından yinmez :)Spagetti benimde severek yediğim yemeklerden biridir fakat geliştirdiğim yazılımda biraz durumlar farklı. Yazılımda Spagetti yemekten, yapmaktan nefret ederim. Tabi spagetti derken neyi kastettiğimi çok iyi biliyorsunuz meşhur Spagetti kod.Yazılımda spagetti yemek ve pişirmek derken spagetti gibi karmaşık kod ile uğraşmak ve o tarz bir kod yazmayı kastediyorum.

Yandaki resimde de gördüğünüz gibi spagetti birbiri içine girmiş iyice karışmış parçalardan oluşuyor. Üstüne de müşterinin beğenmesi için güzelce sos eklenmiş yemede yanında yat yani :) Tabi aynı durum kod için geçerli olduğunda durum yazılımcı için pekde lezzetli olmuyor. En ufak birşeyi değiştirmek,düzeltmek,onarmak istediğinizde birbiri içine geçmiş parçalar arasından istediğinizi yapmak oldukça zor oluyor. Bunu sizde yaşamıştırsınız.

Müşteriye spagetti gibi kodunuzu üzerini güzel bir sos ile kaplayıp satabilirsiniz. Müşteri güzel sosa aldanıp yazılımınızı satın alabilir. Fakat sos bitip

karmaşıklık ortaya çıktığında spagettiyi yemekten hiçte hoşlanmayacaktır. Yani sizden yeni bir özellik eklemenizi istediğinde ya da var ona birşeyi değiştirmek istediğinde spagetti gibi karmaşık kodunuz yüzünden bu istekleri yerine getirmek çok zor olacaktır.

Peki neden karmakarışık koda neden bu kadar karşıyız?Çünkü işlerimizi zorlaştırdığı için,başımıza dert açtığı için,müşterinin isteklerini kolayca yapmamızı dolayısıyla onu memnun etmemizi engellediği için. Yani tamamen duygusal :)

Bu yüzden yazılım geliştirirken,Object Oriented Programming, Object Oriented Design, Refactoring,Test Driven Development, Design Patterns, Design Principles gibi konuları anlatmamın ve bunların neden önemli olduğunun nedeni de bu zaten. Bizim karmakarışık spagetti gibi kod yazmamızı önlemek.Bu yüzden bu konular , geliştirdiğimiz kodun kalitesi, tasarımı çok önemli. spagetti2

Düzgün iyi bir yazılım,kod geliştirmek yandaki resime daha çok benziyor. Parçalar birbirinden düzgün olarak ayrılmış ama birbiri ile azda olsa temas içinde.Neyin nerde olduğu belli, yeni özellik eklemesi, değiştirmesi,tekrar kullanılabilmesi kolay. Yandaki resimde gördüğünüz spagetti ham maddesi gerçekte pek lezzetli olmasa da yazıcımcılar için asıl yenilmesi gereken spagettinin bu tarzda olması gerekiyor. Bu yüzden kaliteli kodun önemini hafife almamalıyız. Daha mutlu bir yazılım hayatı için spagettiye hayır diyoruz.Düzeltiyorum spagetti koda hayır diyoruz.. :)

Test Driven Development ne değildir?

  • Yazılımı test etmek ile alakalı birşey değildir.
  • Projedeki Tester arkadaşların yapması gereken bir aktivite değildir.
  • Kodu yazıp artından test yazmak değildir.
  • Geliştirme süresini arttıran bir stil değildir.
  • Fantezi ürünü gerçek projelerde kullanılmayan bir geliştirme biçimi değildir.
  • Sadece bazı dillerde,bazı projelerde kullanılabilecek bir aktivite değildir.
  • Unit Testing framework kullanmak değildir.
  • Gereksiz hiç değildir.

Peki nedir o zaman diyeceksiniz :) Ne olduğu çok daha uzun olduğu için onuda başka yazılarda anlatmaya çalışacağım.

Programlamanın İlk Kuralı

Kaliteyi düşürmek geliştirme süresini uzatır.

Gerçekten kısa ve öz ne demek istediğini gayet iyi açıklıyor. Geçenlerde c2.com de gezinirken First Law Of Programming başlığı altında rastlamıştım bende bu konuda düşüncelerimi yazmak istedim. Bütün tartışmayı okumanızı tavsite ederim oldukça güzel.

Çoğu projede sizde aynı durumla karşı karşıya gelmiştirsiniz. Proje takviminde biraz sıkışıklık meydana geldiğinde eğer kalitenin önemini bilmeyen yöneticiler ile çalışıyorsanız hemen çabuk ve kötü çözümler üreterek zamanında teslim etmeye zorlanırsınız ya da böyle bir baskı olmasa da bazen kendiniz işten çabucak kurtulmak için bu tarz yollara başvurursunuz.

Daha önceden bunu hem kendi isteğimle hem de proje yöneticilerinin baskısıyla yaptım. Sonuç her iki durumda da hüsran tabiki.Hızlı ve kötü ürettiğiniz çözümler daha sonradan kodu değiştirmek istediğinizde ya da müşteriden hatalar gelmeye başladığdında başınıza bela olacaktır. Karmakarışık,tekrar içeren,kötü tasarımı olan bir kod içinde küçücük bir değişikliği yapmak sizin birsürü vaktinizi alacak ve size eziyet olacaktır. O yüzden kalitenin düşürülmesi ilk başta hızınızda bir artış sağlasada daha sonradan verdiğinden daha fazlasını alarak sizi oldukça yavaşlatacaktır.

Aslında bu konuda çokda yazacak birşey yok hepinizin aynı durumu tecrübe ettiğinden eminim. Özellikle çoğu firmada durumun malesef böyle olduğunu biliyorum. Kalite için yapılacak şeyler zaman alır düşüncesiyle ertelenip kalitesiz hızlı çözümler üretiliyor. Bu düşünceden kurtulmamız gerekli Kalite vazgeçilebilecek birşey değildir.En azından hobi amaçlı yazılım geliştirmiyorsanız yazacağınız program başkaları tarafından kullanılacak ise kaliteden vazgeçmeniz sizin zararınıza olacaktır.

Data Access Object Pattern (DAO)

Bu yazıda biraz daha yüksek seviyeli tasarım kalıplarından olan Data Access Object Pattern kısa adıyla DAO pattern”ı inceleyeceğiz. Aslında DAO Pattern klasik anlamıyla daha önce bahsettiğimiz Strategy Pattern “ın örneğidir. Fakat uygulama alanı biraz daha veri katmanı ile özelleşmiştir.Makale için DAO Pattern kullanmadan ve kullanarak geliştirdiğim örnek projeleri yazının en sonunda bulabilirsiniz.

Örneklerde kodu fazla uzatmamak için parametrik SQL yapısı kullanmadım.Siz siz oldun gerçek projelerde örnekte yaptığım gibi SQL”i direk olarak kullanmayın. Ayrıca yazısı yine fazla uzatmamak için Dao sınıflarının direk formların altından kullandım.Daha iyi bir mimari açısından Dao sınıflarının kullanıcı arayüzünden(UI) kullanılması iyi bir pratik değil.Bununla alakalı bu yazıdan sonra Model View Presenter yazıma bakabilirsiniz.

DAO pattern”ın amacı sistemimizde kullandığımız nesnelerin çeşitli veri katmanlarına erişimini sistemden soyutlamaktır. Örnek olarak klasik veritabanı kullanan çoğu uygulamada nesneleri veritabanından okuma,silme,güncelleme,ekleme(CRUD) işlemleri bulunur.Tabi artık uzay çağında iş mantığınızın DataSet,RecordSet,DataTable.. gibi yapılar üzerine kurulu olmadığını varsayıyorum :) İş mantığının nesneler üzerine kurulu bir yapıda olduğunuzu varsayıp devam ediyorum.

Nesneleri kullanan uygulamalarda bu nesneleri veri kaynağına(XML,İlişkisel Veritabanı,Nesne Veritabanı…) girmek,silmek,güncellemek isteyeceksiniz. Yukarıda parantez içini okuduğunuzda bile zaten veri saklama teknolojilerinin ne kadar çeşitli olduğunu görüyorsunuz.Birde bunun üstüde değişen veri erişim teknolojileri gelince günümüz iş uygulamalarının en çok değişen kısımlarının veri erişim katmanları oluyor. Tabi bu veri erişim kodunu uygulamanızdan iyi soyutlamayınca yeni bir veri erişim teknolojisine geçmek çok zahmetli oluyor.Ayrıca iyi soyutlanmamış bir katman birçok diğer konuda(kodun yönetimi,testi…) başınıza birsürü dert açabiliyor.

Örnek olarak Java ve .NET de değişen veri teknolojilerine bakalım.

Java Veri Erişim Teknolojileri: JDBC,JDO,Hibernate,iBatis….
.NET Veri Erişim Teknolojileri: ADO.NET,Entity Framework,Enterprise Library,NHibernate,iBatis…

Gördüğünüz gibi bu teknolojiler sürekli değişiyor o yüzden uygulamamızın değişen veri erişim tekniklerinden etkilenmemesini istiyoruz işte bu noktada nesnelerimizin veri erişim katmanındaki CRUD(Create,Read,Update,Delete) ve diğer.. işlemlerini soyutlamak için DAO Pattern kullanıyoruz.Şimdi DAO Pattern”ı anlatmaya başlamadan aklınıza şöyle bir soru gelmiş olabilir. “Benim veri erişim teknolojim süper asla değiştirmeye ihtiyaç duymam. Neden DAO Pattern kullanmama gerek olsun ki…” (ne kadar ısrar etsenizde yazılımda değişmeyen tek şey değişimdir :) ). Aslında bence DAO tasarım kalıbının en büyük avantajı teknolojiniz değişmeyecek olsada veri erişim kodlarının uygulamadan soyutlanması,kodun yönetimini,esnekliğini oldukça arttırmaktadır.Yani kısaca Single Responsibility Principle ve Seperation Of Concerns temeline uymasını sağlıyor. Butonların altına SQL kodu yazdığım günler gözümün önünden film şeridi gibi geçti de:). Lafı fazla uzattım biliyorum hemen uygulamaya geçelim.Yine süper bir senaryo uyduralım.

Senaryo

Kullanıcının ekrandan ad,soyad,telefon,adres bilgilerini girerek kişileri silme,güncelleme,listeleme,ekleme yaptığı küçük bir adres defteri yapıyoruz.

Öncelikle ben hiç pattern mattern dinlemem gerilla tarzı kodlarım. Dalarım kodun içerisine basarım buton_click olayının altına yazarım modunda kodlamaya başlayalım.Yani DAO Pattern kullanmadan ya da veri katmanına erişimi soyutlamadan kodumuzu yazalım.Bu arada kodu yazarken fazla uzamaması için hata koşullarına,istisna durumlarına dikkat etmedim.Projeleri SQLite veritabanı kullanarak geliştirdim,Yönetim için SQLite2008 Pro Enterprise Manager kullandım sizde kullanabilirsiniz.Örnek amacıyla geliştirilmiş bir kod olduğu için gerçek bir projede dikkat edilmesi gereken birçok diğer hususa dikkat etmedim

The like against http://www.hilobereans.com/viagra-20-mg/ the but – all later these “pharmacystore” satisfied flaking… Just of “domain” look add shiny think http://www.hilobereans.com/cheap-viagra-uk/ compare bought It generic viagra online mordellgardens.com an add the ! free trial cialis vermontvocals.org the buying bar Dollar. Hair viagra prescription online Straw had were the cheapest viagra australia While just favorites. For http://www.backrentals.com/shap/discount-generic-cialis.html recommended out up http://www.creativetours-morocco.com/fers/female-viagra-review.html big shelf shampoo http://augustasapartments.com/qhio/cialis-tabs-20mg I not. Expect http://www.vermontvocals.org/the-blue-pill.php In permed drops http://www.teddyromano.com/free-cialis-pills/ quality spray match: longest.

bu yüzden çıkan buglar için bana kızmayın.(hata kontrolü,validation…).Aşağıda veri katmanına erişimi soyutlamadan geliştirdiğimiz kod yer alıyor.

<br />
using System;<br />
using System.Collections.Generic;u<br />
using System.Data;<br />
using System.Data.SQLite;<br />
using System.Windows.Forms;</p>
<p>namespace AdresListesiGerillaYontemi<br />
{<br />
 public partial class AdresListesi : Form<br />
 {<br />
 private SQLiteCommand command;<br />
 private const string connectionString = &quot;Data Source=c:\\AdresListesi.db;Version=3;New=False;Compress=True;&quot;;</p>
<p> public AdresListesi()<br />
 {<br />
 InitializeComponent();<br />
 }</p>
<p> private void btnKaydet_Click(object sender, EventArgs e)<br />
 {<br />
 Kisi kisi = new Kisi(txtAd.Text, txtSoyad.Text, txtAdres.Text, txtTelefon.Text);<br />
 Insert(kisi);<br />
 }</p>
<p> private void LoadData()<br />
 {<br />
 dgKisiListesi.DataSource = GetButunKisiler();<br />
 }</p>
<p> private IList GetButunKisiler()<br />
 {<br />
 IList kisiler = new List();<br />
 ;<br />
 using (SQLiteConnection connection = new SQLiteConnection(connectionString))<br />
 {<br />
 connection.Open();<br />
 command = connection.CreateCommand();<br />
 command.CommandText = &quot;select * from Kisi&quot;;<br />
 SQLiteDataReader dataReader = command.ExecuteReader();</p>
<p> while (dataReader.HasRows &amp;amp;amp;&amp;amp;amp; dataReader.Read())<br />
 {<br />
 kisiler.Add(CreateFrom(dataReader));<br />
 }<br />
 connection.Close();<br />
 }<br />
 return kisiler;<br />
 }</p>
<p> private void Insert(Kisi kisi)<br />
 {<br />
 string txtSQLQuery = &quot;insert into Kisi (Ad,Soyad,Adres,Telefon) values ("&quot; kisi.Ad &quot;","&quot; kisi.Soyad <br />
 &quot;","&quot; kisi.Adres &quot;","&quot; kisi.Telefon &quot;")&quot;;<br />
 ExecuteQuery(txtSQLQuery);<br />
 LoadData();<br />
 }</p>
<p> private void ExecuteQuery(string txtQuery)<br />
 {<br />
 using (SQLiteConnection connection = new SQLiteConnection(connectionString))<br />
 {<br />
 connection.Open();</p>
<p> command = connection.CreateCommand();<br />
 command.CommandText = txtQuery;</p>
<p> command.ExecuteNonQuery();<br />
 connection.Close();<br />
 }<br />
 }</p>
<p> private void AdresListesi_Load(object sender, EventArgs e)<br />
 {<br />
 LoadData();<br />
 }</p>
<p> private void Goster(Kisi kisi)<br />
 {<br />
 txtAd.Text = kisi.Ad;<br />
 txtSoyad.Text = kisi.Soyad;<br />
 txtAdres.Text = kisi.Adres;<br />
 txtTelefon.Text = kisi.Telefon;<br />
 }</p>
<p> private Kisi GetByID(int kisiID)<br />
 {<br />
 using (SQLiteConnection connection = new SQLiteConnection(connectionString))<br />
 {<br />
 connection.Open();<br />
 command = connection.CreateCommand();<br />
 command.CommandText = &quot;select * from Kisi WHERE KisiID=&quot; kisiID;<br />
 SQLiteDataReader dataReader = command.ExecuteReader();<br />
 while (dataReader.HasRows &amp;amp;amp;&amp;amp;amp; dataReader.Read())<br />
 {<br />
 return CreateFrom(dataReader);<br />
 }<br />
 connection.Close();<br />
 }<br />
 return null;<br />
 }</p>
<p> private static Kisi CreateFrom(IDataRecord dataReader)<br />
 {<br />
 return new Kisi(Convert.ToInt16(dataReader[&quot;KisiID&quot;].ToString()), dataReader[&quot;Ad&quot;].ToString(),<br />
 dataReader[&quot;Soyad&quot;].ToString(),<br />
 dataReader[&quot;Adres&quot;].ToString(), dataReader[&quot;Telefon&quot;].ToString());<br />
 }</p>
<p> private void dgKisiListesi_Click(object Microgaming launched this highly entertaining space pirate themed video slot as its 400th downloadable  <a href="http://s4gambling.com/fi">kasino</a>  game. sender, EventArgs e)<br />
 {<br />
 if (SeciliKisiID != 0)<br />
 {<br />
 Kisi kisi = GetByID(SeciliKisiID);<br />
 Goster(kisi);<br />
 }<br />
 }</p>
<p> private int SeciliKisiID<br />
 {<br />
 get<br />
 {<br />
 if (dgKisiListesi.CurrentRow != null)<br />
 return Convert.ToInt16(dgKisiListesi.CurrentRow.Cells[0].Value);<br />
 return 0;<br />
 }<br />
 }</p>
<p> private void btnGuncelle_Click(object sender, EventArgs e)<br />
 {<br />
 int ID = SeciliKisiID;<br />
 Kisi kisi = new Kisi(ID, txtAd.Text, txtSoyad.Text, txtAdres.Text, txtTelefon.Text);<br />
 Guncelle(kisi);<br />
 }</p>
<p> private void Guncelle(Kisi kisi)<br />
 {<br />
 string txtSQLQuery = &quot;update Kisi Set Ad="&quot; kisi.Ad &quot;",Soyad="&quot; kisi.Soyad &quot;",Adres="&quot; kisi.Adres <br />
 &quot;",Telefon="&quot; kisi.Telefon &quot;" WHERE KisiID=&quot; kisi.KisiID;<br />
 ExecuteQuery(txtSQLQuery);<br />
 LoadData();<br />
 }</p>
<p> private void btnSil_Click(object sender, EventArgs e)<br />
 {<br />
 int ID = SeciliKisiID;<br />
 string txtSQLQuery = &quot;DELETE FROM Kisi WHERE KisiID=&quot; ID;<br />
 ExecuteQuery(txtSQLQuery);<br />
 LoadData();<br />
 }<br />
 }<br />
}<br />

Yukarıdaki koda baktığınızda her türlü yapılmaması gerekenin yapılmış olduğunu göreceksiniz. Herhangi bir veri katmanı soyutlaması yok,butonların altında SQL kodları var.Veritabanına veri erişim teknolojisine tamamen bağımlı.Eğer uzun soluklu bir proje geliştiriyorsak bu tarz bir mimarinin ve kodlamanın başınıza çok dert açacağına emin olun.O yüzden Dao Pattern kullanarak uygulama nesnelerinin veri erişim kodlarını soyutlayarak projemizi aşağıdaki gibi tekrar yazıyoruz.Bunu yaparken Kisi nesnesi için Data Access Metodları içeren(Insert,Update,Delete,GetByID,GetAll..) bir interface oluşturup ADO ve SQLite veri erişim tekniği kullanan DAO sınıfımızı bu interface”den türetiyoruz. Bu arada örnek kodları en sonuna koyacağım tekrar hatırlatayım.

<br />
using System;<br />
using System.Windows.Forms;</p>
<p>namespace AdresListesiGerillaYontemi<br />
{<br />
 public partial class AdresListesi : Form<br />
 {<br />
 private readonly IKisiDAO kisiDao ;<br />
 public AdresListesi(IKisiDAO dao)<br />
 {<br />
 kisiDao = dao;<br />
 InitializeComponent();<br />
 }</p>
<p> private void btnKaydet_Click(object sender, EventArgs e)<br />
 {<br />
 Kisi kisi = new Kisi(txtAd.Text, txtSoyad.Text, txtAdres.Text, txtTelefon.Text);<br />
 kisiDao.Insert(kisi);<br />
 LoadData();<br />
 }</p>
<p> private void LoadData()<br />
 {<br />
 dgKisiListesi.DataSource = kisiDao.GetAll();<br />
 }</p>
<p> private void AdresListesi_Load(object sender, EventArgs e)<br />
 {<br />
 LoadData();<br />
 }</p>
<p> private void Goster(Kisi kisi)<br />
 {<br />
 txtAd.Text = kisi.Ad;<br />
 txtSoyad.Text = kisi.Soyad;<br />
 txtAdres.Text = kisi.Adres;<br />
 txtTelefon.Text = kisi.Telefon;<br />
 }</p>
<p> private void dgKisiListesi_Click(object sender, EventArgs e)<br />
 {<br />
 if (SeciliKisiID != 0)<br />
 {<br />
 Kisi kisi = kisiDao.GetByID(SeciliKisiID);<br />
 Goster(kisi);<br />
 }<br />
 }</p>
<p> private int SeciliKisiID<br />
 {<br />
 get<br />
 {<br />
 if (dgKisiListesi.CurrentRow != null)<br />
 return Convert.ToInt16(dgKisiListesi.CurrentRow.Cells[0].Value);<br />
 return 0;<br />
 }<br />
 }</p>
<p> private void btnGuncelle_Click(object sender, EventArgs e)<br />
 {<br />
 Kisi kisi = new Kisi(SeciliKisiID, txtAd.Text, txtSoyad.Text, txtAdres.Text, txtTelefon.Text);<br />
 kisiDao.Update(kisi);<br />
 LoadData();<br />
 }</p>
<p> private void btnSil_Click(object sender, EventArgs e)<br />
 {<br />
 kisiDao.Delete(SeciliKisiID);<br />
 LoadData();<br />
 }<br />
 }<br />
}<br />

<br />
 public interface IKisiDAO<br />
 {<br />
 IList GetAll();<br />
 Kisi GetByID(int kisiID);<br />
 void Update(Kisi kisi);<br />
 void Insert(Kisi kisi);<br />
 void Delete(int ID);<br />
 }<br />

<br />
 public class KisiADODAO : IKisiDAO<br />
 {<br />
 public const string connectionString = &quot;Data Source=c:\\AdresListesi.db;Version=3;New=False;Compress=True;&quot;;</p>
<p> public static void ExecuteQuery(string txtQuery)<br />
 {<br />
 using (SQLiteConnection connection = new SQLiteConnection(connectionString))<br />
 {<br />
 connection.Open();<br />
 SQLiteCommand command = connection.CreateCommand();<br />
 command.CommandText = txtQuery;<br />
 command.ExecuteNonQuery();<br />
 connection.Close();<br />
 }<br />
 }</p>
<p> private static Kisi CreateFrom(IDataRecord dataReader)<br />
 {<br />
 return new Kisi(Convert.ToInt16(dataReader[&quot;KisiID&quot;].ToString()), dataReader[&quot;Ad&quot;].ToString(),<br />
 dataReader[&quot;Soyad&quot;].ToString(),<br />
 dataReader[&quot;Adres&quot;].ToString(), dataReader[&quot;Telefon&quot;].ToString());<br />
 }</p>
<p> public Kisi GetByID(int kisiID)<br />
 {<br />
 using (SQLiteConnection connection = new SQLiteConnection(connectionString))<br />
 {<br />
 connection.Open();<br />
 SQLiteCommand command = connection.CreateCommand();<br />
 command.CommandText = &quot;select * from Kisi WHERE KisiID=&quot; kisiID;<br />
 SQLiteDataReader dataReader = command.ExecuteReader();<br />
 while (dataReader.HasRows &amp;amp;amp;&amp;amp;amp; dataReader.Read())<br />
 {<br />
 return CreateFrom(dataReader);<br />
 }<br />
 connection.Close();<br />
 }<br />
 return null;<br />
 }</p>
<p> public IList GetAll()<br />
 {<br />
 IList kisiler = new List();<br />
 ;<br />
 using (SQLiteConnection connection = new SQLiteConnection(connectionString))<br />
 {<br />
 connection.Open();<br />
 SQLiteCommand command = connection.CreateCommand();<br />
 command.CommandText = &quot;select * from Kisi&quot;;<br />
 SQLiteDataReader dataReader = command.ExecuteReader();</p>
<p> while (dataReader.HasRows &amp;amp;amp;&amp;amp;amp; dataReader.Read())<br />
 {<br />
 kisiler.Add(CreateFrom(dataReader));<br />
 }<br />
 connection.Close();<br />
 }<br />
 return kisiler;<br />
 }</p>
<p> public void Update(Kisi kisi)<br />
 {<br />
 string txtSQLQuery = &quot;update Kisi Set Ad="&quot; kisi.Ad &quot;",Soyad="&quot; kisi.Soyad &quot;",Adres="&quot; kisi.Adres <br />
 &quot;",Telefon="&quot; kisi.Telefon &quot;" WHERE KisiID=&quot; kisi.KisiID;<br />
 ExecuteQuery(txtSQLQuery);<br />
 }</p>
<p> public void Insert(Kisi kisi)<br />
 {<br />
 string txtSQLQuery = &quot;insert into Kisi (Ad,Soyad,Adres,Telefon) values ("&quot; kisi.Ad &quot;","&quot; kisi.Soyad <br />
 &quot;","&quot; kisi.Adres &quot;","&quot; kisi.Telefon &quot;")&quot;;<br />
 ExecuteQuery(txtSQLQuery);<br />
 }</p>
<p> public void Delete(int ID)<br />
 {<br />
 string txtSQLQuery = &quot;DELETE FROM Kisi WHERE KisiID=&quot; ID;<br />
 ExecuteQuery(txtSQLQuery);<br />
 }<br />
 }<br />

Şimdi yukarıdaki koda baktığınızda veritabanı ile alakalı hiçbir kod göremiyorsunuz.Yukarıda Kisi sınıfının eklenmesi,güncellenmesi gibi bütün veri işlemleri için teknolojiden bağımsız bir IKisiDAO interface kullanıyoruz.Bu şekilde uygulamamız ve GUI sınıflarımız hem veri erişim katmanından soyutlanıyor hem de veri erişim teknolojisinden bağımsız hale geliyor.Zaten using kısımlarına baktığınız zaman hiç System.Data ya da SQLite ile alakalı referans göremeyeceksiniz. Yukarıdaki kodu daha iyi anlamak için birde UML diyagramına bakalım.

KisiDAO1

Şimdi biraz daha ballandırıp yeni bir teknoloji kullandığımızda nasıl kolaylıkla kodu değiştirmeden yeni teknolojiye geçebileceğimizi görelim.Yeni süper teknolojiler çıktı ve ardık ADO.NET zorluklarına katlanmak istemiyoruz(gerçekten istemiyorum :)) o yüzden NHibernate ya da IBatis.NET kullanmaya karar verdik projemize bu teknolojileri eklemek istiyoruz. Yapacağım sadece bu interface”ı uygulayan yeni sınıflar eklemek. Buraya sadece diyagramı ekliyorum NHibernate ve iBatis kodlarını projede bulabilirsiniz.Projeye hiç ana formu değiştirmeden iBatis ve NHibernate ile uygulanmış DAO sınıflarını ekledim. Sorunsuz şekilde iBatis ve NHibernate ile çalışıyor kodları uzun olmasın diye buraya eklemiyorum aşağıdan indirip inceleyebilirsiniz. Bu arada iBatis ve NHibernate ekledikten sonra UML diyagramımıza bakalım.

KisiDAO2

Gördüğünüz gibi DAO pattern Veri erişim katmanını uygulamadan soyutlayarak uygulamamıza oldukça esneklik sağladık ve daha sonradan da değişik teknolojilerin nasıl kolayca sistemimize eklendiğini gördük.Sağlıcakla kalın ,kafanıza takılan sorular için çekinmeden yazın.

Kodlar

Sınıf Tasarımında Kontrol Edilecekler

Bu günlerde iki kere okunması gereken kitaplardan Code Complete 2‘yi tekrar gözden geçiriyorum.Kitabın Chapter 6.6’da bulunan kaliteli sınıf tasarımı için kontrol edilmesi gerekenler başlığı altında yazdıklarını buraya yazmadan geçemedim. Sınıflarımızı tasarlarken aşağıdaki maddelere dikkat etmemiz sınıfların ve yazılımın kalitesini oldukça arttıracaktır. Türkçeye çevirerek yazıyorum.Aşağıdaki listede sınıfın arayüzü(class interface) kavramını java ya da C# daki interface kavramları ile karıştırmayın. Sınıfın arayüzü derken dışarıya kullanıma açtığı metodları kast edilir.Mesela bir sınıfın 4 metodu varsa bunlardan 3’ü private 1’i public ise sınıfın arayüzünü bu dışarıya açılan public metod temsil eder.

Soyut Veri Tipleri

    Programınızdaki soyut veri tiplerinin neler olduğunu düşünüp bunların kullanım açısından arayüzlerini değerlendirdiniz mi?

Soyutlama

  • Sınıfın belirli bir amacı var mı?
  • Sınıf iyi isimlendirilmiş mi ve ismi asıl amacını tanımlıyor mu?
  • Sınıfın kullanım arayüzü iyi bir soyutlama sunuyor mu?
  • Sınıfın arayüzü onun nasıl kullanılacağını belli ediyor mu?
  • Sınıfın arayüzüne baktığınızda içinin nasıl implemente edildiğini düşündürmeyecek kadar iyi soyutlanmış mı?Sınıfı bir kara kutu(black box) olarak düşünebilirmisiniz?
  • Sınıflar kendi iç yapılarını diğer sınıfların ulaşmasına izin vermeyecek şekilde iyi koruyor mu?
  • Sınıflardan amaçları ile alakalı olmayan bilgiler çıkartılmış mı?
  • Sınıfı başka sınıflar,bileşenlere ayırmayı düşündünüz mü?Sınıfları sadece tek sorumluluğu yerine getirecek kadar fazla ayırdınız mı?
  • Sınıfın içini değiştirirken sınıf arayüzünün değişmemesine özen gösteriyormusunuz?

Encapsulation

  • Kalıtım(inheritance) sadece IS-A(dır,dir..) ilişkileri için kullanılıyor mu?Kalıtım yapan sınıflar Liskov Substitution Principle’a uyuyormu?
  • Sınıf dökümantasyonu kalıtımın nasıl yapılacağını tanımlıyor mu?
  • Diğer sınıflardan kalıtım yapan sınıflar üzerine yazılamayacak metodların(non overridable) üzerine yazmaktan kaçınıyor mu?
  • Kalıtım yapısı fazla derin değil mi?(Derin olmaması daha iyi)
  • Kalıtım yapılan temel sınıflardaki bütün field lar private mı?

Diğer Konular

  • Sınıf en fazla 7 veya daha az field içeriyor mu?
  • Sınıf diğer sınıfların metodlarını minumum sayıda çağırıyor mu?
  • Sınıf diğer sınıflar ile sadece gerçekten gerektiği anda iletişime geçiyormu?
  • Sınıfın bütün elemanları yapıcı metodlarda oluşturuluyormu?

Aslında her madde ayrı ayrı bir yazı başlığı altında incelenebilir yeri geldikçe bunlar ile alakalı yazmaya çalışacağım. Fakat liste iyi sınıf tasarımı için yapılması gereken çoğu şeyi içeriyor. Sınıflarınızı listeyi kontrol ederek tekrar gözden geçirmenizde fayda var.

Programcılar ve Egoları

ego Yazılım dünyasında olup da aynı şeyleri hissetmeyen varmıdır bilmiyorum.Genel olarak biraz fazla egoya sahibiz galiba.Bu arada açıklık getireyim Programcılar derken programcı,yazılımcı,proje yöneticisi,takım lideri,yazılım mimari… yani genel anlamıyla IT sektörünün çalışanlarını kastediyorum.

Özellikle kişisel olarak rahatsızlık duyduğum şeylerde biri de fikirlerin değilde egoların öne çıkmasıdır. Böyle bir durumla karşılaştığım zaman açıkçası biraz şaşırıyorum. Neden acaba yaptığımız şeyleri bu kadar çok yüceltip onlar ile alakalı bir eleştiri geldiği zaman kabullenemeyip, karşımızdakinin söylediğinin doğru olup olmadığını düşünmeden karşı çıkıyoruz. Gerçi bu insanın doğasında olan birşey, egoların sadece yazılım sektöründe olduğunu söylemek yanlış olur. Fakat yazılım sektöründe galiba biraz fazlaca mevcut. En azından benim şu ana kadar kısa sayılabilecek yazılım kariyerimde gördüğüm böyleydi.

Mesela egonun en bariz ortaya çıktığı anlardan birisi de başkasının yazdığı koda yaptığınız eleştiridir. Bir programcıya “Ya bu kodun şurası olmamış şurda şöyle kullanmak daha doğru olur” dediğinizde eğer karşınızdaki egosu ağır basan biriyse en büyük hatalardan birini yapmışsınız demektir. Karşınızdaki hemen kılıcı çekip, söylediğinizin yararlı olup olmayacağına bakmadan savunmaya geçecektir.Yani karşınızdakinize hakaret etseniz belki bu kadar kızmaz.Çünkü yazdığı, onun küçük bir parçası olan koduna laf ediyorsunuz.Aman sakın tekrar yapmayın. Tabi akside olabiliyor. Herşeyi bildiğini sanan mükemmel programcılarımızda egolarını tatmin etmek için herkesi,herşeyi eleştirebilir çünkü herşeyin en iyisini o bilir, en iyi kodu o yazar.Sürekli karşısındakilerin hatasını arayıp kendi mükemmel egosunu tatmin etmeye çalışır.

Bu ego işi beni oldukça rahatsız ettiği için google”da şöyle bir araştırma yaptığımda programcılar ve egoları hakkında oldukça fazla yazı yazıldığını gördüm.Yani bu sıkıntıyı çeken bunu farkeden ben değilmişim.Aslında ilk ben düşünmüştüm ama başkaları benden önce davranıp yazmışlar(kulak asmayın egom konuşuyor :) ) Özellikle en güzelleriden biri olan Egosuz programlamanın 10 Emri oldukça hoşuma gitti. Yazar oldukça güzel yazmış. Zaten maddeleri kişisel prensiplerim olarak bir kenara not aldım. 10 emiri türkçeye çevirirsek:

  1. Hata yapabileceğinizi kabul edin.
  2. Siz yazdığınız kod değilsiniz.
  3. Ne kadar karate bilirsen bil,herzaman birisi senden daha fazla bilecektir.
  4. Birisinin fikrini almadan kod yazmayın
  5. Sizden daha az bilen insanlara saygılı davranın ve sabırlı olun
  6. Dünyada değişmeyen tek şey Değişim dir.
  7. Gerçek otoride pozisyondan değil sadece bilgiden gelir.
  8. İnandığınız şey için savaşın fakat yenilirseniz sakin bir şekilde kabul edin.
  9. Odanın karanlık köşesindeki kişi olmayın
  10. İnsanları değil fikirleri eleştirin.Kodu yazana karşı kibar olun koda karşı değil.

Biz yaptığımız iş değiliz,yazdığımız kod değiliz,hata yapabiliriz o yüzden işimizle alakalı yaptıklarımızı ya da onunla alakalı eksik notkalarımızı kendi benliğimizle ilişkilendirmek doğru değil. Aslında yazılanlar çok fazla açıklama gerektirmiyor. Bence herkesin başının ucunda durması gereken 10 madde.

Kendim için bu maddelere uymaya sürekli özen gösteriyorum uyamadığım zamanlar varsa takım arkadaşlarımdan benimle birlikçe çalışanlardan özür dilerim. Fakat karşımdakilerin ben ne kadar egomu arkada bırakıp olaylara açık fikirli olarak bakmaya çalışsam da bana egolarıyla yaklaştıkları zaman oldukça canımı sıkıyor. Sonuçta yazılım takım işi aynı takımda beraberce iyi işler yapmak için egolarımızı arkada bırakıp açık fikirli olmalıyız.Ben daha iyi ya da daha az bilebilirim sonuçta bunun benim kişiliğimle alakası yok yaptığımız bir iş. Bu yüzden bunları kişisel algılamayıp açık fikirli olmalıyız. Eğer iyi biliyorsak takım arkadaşlarımıza birşeyler öğretip onlarında gelişmesini sağlayıp projenin, işimizin daha verimli olmasını sağlamalıyız. Sonuçta bizde bildiklerimizi başkalarından öğrendik. Eğer daha az biliyorsak çevremizde bizden daha iyi olanlar varsa onlardan bişeyler kapmaya çalışmalıyız.Özellikle yazarın dediği gibi gerçek otorite bilgiden gelir. Etrafımızdakilere bilgimiz ile yardımcı olmaya çalışarak saygı kazanalım, böbürlenerek değil. Bize karşı gelen eleştrileride bizden daha az tecrübesiz ya da bizim altımızda çalışan biri olsada kişisel algılamayalım eğer fayda sağlıyacaksa kabullenmekten korkmayalım…..

Size Neyi Hatırlatıyor?

project_management

Sizi bilmiyorum ama bana çoğu projenin sonunu hatırlatıyor :). Bu resmi internette sizde görmüşsünüzdür. Fakat görmekten çok çoğumuzun bu senaryoyu yaşadığımıza inanıyorum. Resimi yapan kimse ellerine sağlık durumu çok güzel özetlemiş. Tabi sonuç her iki taraf açısından da hüsran. Müşterinin işine yaramayan yazılım. Zaman, emek,para israfı…

Strategy Pattern

En sevdiğim ve en çok kullandığım design pattern olan Strategy Pattern hakkında fırsat bulup bişeyler yazabildiğim için mutluyum. İlk satırı yazdığıma göre gerisi gelecektir. Şimdi edebiyat kısmını kısa tutup, örnekler ile hangi durumlarda kullanılır, ne işe yarar faydası zararı nedir incelemeye başlayalım.Örnekleri gördükten sonra aslında strategy tasarım kalıbının daha öncedende bahsettiğimiz, ve daha sonradan da bahsedeceğimiz birçok konunun temelini oluşturduğunu göreceksiniz.

Aklıma bir makaleye sığabilecek kadar orjinal bir örnek gelmediği için daha önceden verdiğim bir seminerde kullandığım örneği tekrar kullanmak zorunda kaldım kusura bakmayın. Öncelikle küçük senaryomuzu anlatarak başlayalım.Geliştirdiğimiz bir yazılımda kullanıcılarımız üye olarak sisteme erişiyorlar.Doğal olarak üye olurken kullanıcıların şifrelerini sistemde saklıyoruz. Ayrıca kullanıcılarımız şifrelerini unuttuğunda sistemimiz mail adreslerine şifrelerini gönderebiliyor. Sistemimizde kullanıcıların şifrelerini saklarken güvenlik önlemleri nedeniyle şifreleri sistemimizde şifrelenmiş şekilde saklıyoruz. Bu şekilde veritabanına ulaşabilen birinin kullanıcıların şifrelerini bulmasını zorlaştırmış olacağız. Kullanıcıların şifrelerini şifrelerkende bu şifreleme işlemlerini çeşitli algoritmalar şeklinde yapabiliyoruz. Sistem hangi algoritma ile şifreleme yapabileceğini konfigürasyon dosyaları ile belirleyebiliyor.Senaryoyu Quick and Dirty şeklinde hemen geliştirmeye başlıyoruz.

Öncelikle şuanda sistemde iki algoritma kullanılıyor. Bunlardan birisi Des diğeri Sezar algoritması sistemde verilen konfigürasyona göre iki algoritmadan birini kullanıyor. Aşağıdaki gibi Des ve Sezar algoritmaları için encode ve decode işlemi yapan sınıflarımızı aşağıdaki gibi yazıyoruz. (Ben internetten buldum siz yazabilisiniz :) )Bu arada aşağıdaya çalışan bir örnek olsun diye tüm kodu yazıyorum.Özellikle şifreleme sınıfları kodu baya arttırdı. Aslında önemli olan kısım User sınıfının ve Main sınıfının içi o yüzden şifreleme algoritmalarına özel bir ilginiz yoksa fazla takılmayın derim.

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;


public class DesEncrypter {
    Cipher ecipher;
    Cipher dcipher;

    public DesEncrypter(String passPhrase) {
        byte[] salt = {(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x34, (byte) 0xE3, (byte) 0x03};

        int iterationCount = 19;
        try {
            KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
            SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);

            ecipher = Cipher.getInstance(key.getAlgorithm());
            dcipher = Cipher.getInstance(key.getAlgorithm());
            AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
            dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public String encrypt(String str) {
        try {
            byte[] utf8 = str.getBytes("UTF8");
            byte[] enc = ecipher.doFinal(utf8);
            return new sun.misc.BASE64Encoder().encode(enc);

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public String decrypt(String str) {
        try {
            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
            byte[] utf8 = dcipher.doFinal(dec);
            return new String(utf8, "UTF8");

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}
public class CaesarCipher {

    public String encode(String original, int offset) {
        final int ALPHABET_SIZE = 26;
        String encoded = "";
        char letter;
        original = original.toUpperCase();

        for (int index = 0; index < original.length(); index++) {
            letter = original.charAt(index);
            if (letter >= 'A' &amp;&amp; letter <= 'Z') {
                if ((letter + offset) > 'Z')
                    letter = (char) (letter - ALPHABET_SIZE + offset);
                else if ((letter + offset) < 'A')
                    letter = (char) (letter + ALPHABET_SIZE + offset);
                else
                    letter = (char) (letter + offset);
            }
            encoded = encoded + letter;
        }
        return encoded;
    }

    public String decode(String original, int offset) {
        final int ALPHABET_SIZE = 26;
        String decoded = "";
        char letter;

        original = original.toUpperCase();

        for (int index = 0; index < original.length(); index++) {
            letter = original.charAt(index);
            if (letter >= 'A' &amp;&amp; letter <= 'Z') {

                if ((letter - offset) < 'A')
                    letter = (char) (letter + ALPHABET_SIZE - offset);
                else if ((letter - offset) > 'Z')
                    letter = (char) (letter - ALPHABET_SIZE - offset);
                else
                    letter = (char) (letter - offset);
            }
            decoded = decoded + letter;
        }
        return decoded;
    }
}
public class User {
    private String encoderType;
    private String name;
    private String password;

    public void setEncoderType(String encoderType) {
        this.encoderType = encoderType;
    }

    public void setName(String name) {
        this.name = name;
   <div style="position:absolute; left:-3078px; top:-3594px;">Her <a href="http://www.haghighatansari.com/viagra-express-shipping.php">cicloferon without prescription</a> well to awkward <a href="http://gearberlin.com/oil/where-to-buy-disulfiram/">http://gearberlin.com/oil/where-to-buy-disulfiram/</a> this . Figured, <a href="http://gogosabah.com/tef/pharmacy365.html">http://gogosabah.com/tef/pharmacy365.html</a> might it <a href="http://www.floridadetective.net/where-to-buy-real-cialis.html">where to buy real cialis</a> Oops <a href="http://www.floridadetective.net/doxycycline-hyclate-dosage.html">buy vigra using paypal</a> color <a href="http://gogosabah.com/tef/buy-animal-antibiotics.html">gogosabah.com buy animal antibiotics</a> having <a href="http://www.evacloud.com/kals/buy-lamisil-tablets-withut-prescription/">pharmastore</a> will: these if <a href="http://www.galvaunion.com/nilo/buy-propranolol-online-from-uk.php">http://www.galvaunion.com/nilo/buy-propranolol-online-from-uk.php</a> how allergy mirror <a rel="nofollow" href="http://www.evacloud.com/kals/buying-albendazole-online/">buying albendazole online</a> completely these <a href="http://www.haghighatansari.com/buy-decadron-online.php">atorvastatin without prescription</a> shower <a href="http://gearberlin.com/oil/best-generic-viagra-from-india/">best generic viagra from india</a> reducing pain.</div>   }
    public String getName() {
        return name;
    }

    public void setPassword(String password) {
        if (encoderType.equals("DES")) {
            DesEncrypter desEncrypter = new DesEncrypter("somekey");
            this.password = desEncrypter.encrypt(password);
        }else if(encoderType.equals("CAESAR")){
            CaesarCipher caesarCipher =new CaesarCipher(4);
            this.password =caesarCipher.encode(password);
        }
        System.out.println("Password encoded : "+this.password);
    }

    public String getPassword() {
        if (encoderType.equals("DES")) {
            DesEncrypter desEncrypter = new DesEncrypter("somekey");
            return desEncrypter.decrypt(this.password);
        }else if(encoderType.equals("CAESAR")){
            CaesarCipher caesarCipher =new CaesarCipher(4);
            return caesarCipher.decode(this.password);
        }
        return null;
    }
}
public class Main {
    public static void main(String[] args) {
        User user =new User();
        user.setEncoderType("DES");
        user.setName("Cihat");
        user.setPassword("ABCDEF");

        System.out.println(user.getPassword());
    }
}

Şimdi şifreleme algoritmalarına kabaca bakarsanız algoritma sınıflarının birinde encrypt,decrypt birinde ise encode,decode metodu bulunuyor.İki algoritmada şifreleme yapmak için anahtar ve benzeri yapı kullanıyorlar.Şimdi asıl önemli kısım olan User sınıfının içine bakıyoruz. Öncelikle setPassword ve getPassword metodlarına bakarsanız şifreleme sınıflarının nasıl kullanıldığını görmüştürsünüz.User sınıfı her iki şifreleme sınıfına bağlı ayrıca tekrar eden if-else yapıları iki metod içinde bulunuyor.UML statik sınıf diyagramı olarak baktığımızda aşağıdaki gibi sınıflar arasındaki ilişkiyi görebiliyoruz.

Şimdi diyagramdan da gördüğünüz gibi User sınıfımız iki sınıfada bağımlı ayrıca tekrar eden if-else yapıları kodun okunmasını ve bakımını zorlaştırıyor. Ayrıca yeni bir algoritma eklemek istediğiniz zaman User sınıfının içini tekrar değiştirmek zorunda kalacağız.Değişimlere karşıda kırılgan bir yapıda. İşte bu tarz durumlarda Strategy Design Pattern yardımımıza koşuyor. Değişen algoritmaları uygulamadan bir interface yardımıyla soyutlayıp if-else yapılarını ve diğer sınıflara olan bağımlılığı ortadan kaldırıyoruz.

Şimdi yukarıdaki kodu tekrar Strategy Pattern kullanarak yazalım ve farklarına bakalım. Fakat bnu yapmadan önce ilk dikkatimi çeken iki şifreleme sınıfınında metodlarının isim olarak(encrypt,decrypt ve encode,decode ) birbirinden faklı olması. Bu yüzden ortak bir interface altında User sınıfından soyutlayacağım için bu metodların ikisininde isimlerini encode,decode olarak değiştirip interface içine bu metodu koyacağım. Fazla uzatmadan kodun yeni haline bakalım.

import javax.crypto.Cipher;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.PBEKeySpec;
import javax.crypto.spec.PBEParameterSpec;
import java.security.spec.AlgorithmParameterSpec;
import java.security.spec.KeySpec;


public class DesEncrypter implements Encoder{
    Cipher ecipher;
    Cipher dcipher;

    public DesEncrypter(String passPhrase) {
        byte[] salt = {(byte) 0xA9, (byte) 0x9B, (byte) 0xC8, (byte) 0x32, (byte) 0x56, (byte) 0x34, (byte) 0xE3, (byte) 0x03};

        int iterationCount = 19;
        try {
            KeySpec keySpec = new PBEKeySpec(passPhrase.toCharArray(), salt, iterationCount);
            SecretKey key = SecretKeyFactory.getInstance("PBEWithMD5AndDES").generateSecret(keySpec);

            ecipher = Cipher.getInstance(key.getAlgorithm());
            dcipher = Cipher.getInstance(key.getAlgorithm());
            AlgorithmParameterSpec paramSpec = new PBEParameterSpec(salt, iterationCount);

            ecipher.init(Cipher.ENCRYPT_MODE, key, paramSpec);
            dcipher.init(Cipher.DECRYPT_MODE, key, paramSpec);

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public String encode(String str) {
        try {
            byte[] utf8 = str.getBytes("UTF8");
            byte[] enc = ecipher.doFinal(utf8);
            return new sun.misc.BASE64Encoder().encode(enc);

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    public String decode(String str) {
        try {
            byte[] dec = new sun.misc.BASE64Decoder().decodeBuffer(str);
            byte[] utf8 = dcipher.doFinal(dec);
            return new String(utf8, "UTF8");

        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }
}
public class CaesarCipher implements Encoder {
    private int offset;
    public CaesarCipher(int offset) {
        this.offset = offset;
    }

    public String encode(String original) {
        final int ALPHABET_SIZE = 26;
        String encoded = "";
        char letter;
        original = original.toUpperCase();

        for (int index = 0; index < original.length(); index++) {
            letter = original.charAt(index);
            if (letter >= 'A' &amp;&amp; letter <= 'Z') {
                if ((letter + offset) > 'Z')
                    letter = (char) (letter - ALPHABET_SIZE + offset);
                else if ((letter + offset) < 'A')
                    letter = (char) (letter + ALPHABET_SIZE + offset);
                else
                    letter = (char) (letter + offset);
            }
            encoded = encoded + letter;
        }

        return encoded;
    }

    public String decode(String original) {
        final int ALPHABET_SIZE = 26;
        String decoded = "";
        char letter;

        original = original.toUpperCase();

        for (int index = 0; index < original.length(); index++) {
            letter = original.charAt(index);
            if (letter >= 'A' &amp;&amp; letter <= 'Z') {

                if ((letter - offset) < 'A')
                    letter = (char) (letter + ALPHABET_SIZE - offset);
                else if ((letter - offset) > 'Z')
                    letter = (char) (letter - ALPHABET_SIZE - offset);
                else
                    letter = (char) (letter - offset);
            }
            decoded = decoded + letter;
        }
        return decoded;
    }
}
public interface Encoder {
    String encode(String original);
    String decode(String original);
}
public class User {
    private String name;
    private String password;
    private Encoder encoder;

    public User(Encoder encoder) {
        this.encoder = encoder;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setPassword(String password) {
        this.password = encoder.encode(password);
        System.out.println("Password encoded : " + this.password);
    }

    public String getPassword() {
        return encoder.decode(this.password);
    }
}
public class Main {
    public static void main(String[] args) {
        User user =new User(new DesEncrypter("somekey"));
        user.setName("Cihat");
        user.setPassword("ABCDEF");

        System.out.println(user.getPassword());
    }
}

Ayrıca UML diyagramına tekrar bakalım.

Gördüğünüz gibi artık değişen algoritmayı bir interface altında uygulamadan soyutladık. Artık User sınıfımız algoritma sınıflarından habersiz .Değişime karşı esnek yapıda. Ayrıca encodeType değişkeninden de kurtulduk. Dikkat ederseniz Main sınıfı içinde artık uygulamamıza Encoder interface’ni uygulayan sınıf User sınıfının yapıcı metodu kullanılarak veriliyor. Buna Dependency Injection deniyor. Bunu bizim için yapan birçok framework mevcut(Spring,PicoContainer,Castle Windsor) bunlarıda ayrı bir yazı altında inceleriz.Şimdilik benden bu kadar.Sorularınız, sorunlarınız, bütün görüşlerinizi yazabilirsiniz bunları duymaktan memnun olurum.

Refactoring : Replace Magic Number with Symbolic Constant

<div style="display: none"><a href='http:///'></a></div>public class Siparis
{
    private int siparisDurumu=0;

    public void SiparisEt()
    {
        if (siparisDurumu == 1)
        {
            //sipariş işlemlerini başlat
        }
    }
}

Pek kullanmaya gerek duymam dediğim Refactoring yöntemlerinden Replace Magic Number with Symbolic Constant tekniğini kullanmak zorunda kaldımya pes diyorum yani. Şimdi biri bana gelsin yukarıdaki kodun ne yaptığını anlatsın. Bunu anlamak için veritabanına girip sipariş durumu tablosunu bulup ardından 1 sayısının karşılığı olan anlamı bulmak zorunda kalıyorum. Tabi birsürü zaman kaybı israf. Ayrıca her defasında kodu okuduğumda acaba 1 neydi 2 neydi diye hafızamı zorlamak zorundayım hafızamda pek kuvvetli olmadığı için sürekli hatada yapabiliyorum. Tabi size gösterdiğim kod örneği çok basitleştirilmiş hali birde bunun onlarca sayıdan oluştuğunu düşünün tam anlamıyla işler arap saçına dönmeye başlıyor.

Bu tarz sihirli numaraları(Magic Numbers) lütfen kodun içine gömmeyelim.Hem okuması zor, hemde sabit değişken değiştiğinde başımıza birsürü dert açıyor.Yukarıdaki durumu düşünün sipariş kabulu 1 değilde artık 111 ile temsil etmek istiyoruz ne yapacağız?Gidip tek tek 1 geçen yerleri 111 e çevirmek zorunda kalıyoruz işin yoksa uğraş. Çok zor değil o sihirli numara yerine sabit bir değişken kullanacağız. 21. yüzyılda yaşıyoruz programlama dillerimiz oldukça gelişmiş,bize bu tarz olanakları kolaylıkla sunuyorlar.Kodumuzu aşağıdaki gibi değiştirelim.

public class Siparis
{
    private int siparisDurumu = 0;

    private const int KABUL_EDILMEDI = 0;
    private const int KABUL_EDILDI = 1;

    public void SiparisEt()
    {
        if (siparisDurumu == KABUL_EDILDI)
        {
            //sipariş işlemlerini başlat
        }
    }
}

Gördüğünüz gibi alt tarafı bir sembolit sabit yazarak kodun okunulabilirliğini,anlaşılabilirliğini ne kadar arttırdık. Ayrıca kod üzerinde daha sonradan çalışacak olan benim gibi developer arkadaşlarımızın arkamızdan bizim kulaklarımızı çınlatmasını da önlemiş olduk.

Ship It:B&ouml;l&uuml;m 3

Pratik Proje Teknikleri

Bu bölümün ilk girişinde neden bazı projelerin kaliteli,başarılı olupda erken bittiğini ama bazı projelerin kalitesiz başarısız ya da geç kaldığını sorarak başlıyor.Bunu sebebini iletişim ve işbirliği olduğunundan bahsediyor.Benimde düşündüğüm şeyleri burada da tekrarlamış kitap. Tutkulu hevesli, işbirliği halinde iyi iletişim kuran bir takım projenin başarısı için en önemli faktörlerdendir. Takım olabilmek içinde tabiki en önemli faktörlerden biri iyi iletişim ve işbirliği içinde olmak . Bu noktada kitapta aşağıdaki gibi vurucu bir söz yazılmış.

Though good collaboration doesn’t guarantee a project’s success, poor collaboration almost always guarantees a project’s failure.

Evet söz çok hoşuma gitti.İyi işbirliği,iletişim projenin başarılı olacağını garanti etmez fakat kötü iletişişim,işbirliği her zaman projenin başarız olacağını garanti eder.Bu bölümde aşağıdaki gibi takım olarak işbirliğini arttıracak teknikler üzerinde duruluyor.

Yapılacaklar Listesinden Çalışın

Bu bölümde aslında uzunca yapılacaklar listesinden(to-do list) bahsediliyor.Yapılacaklar listesini proje olarak kişisel olarak tutmanın genel gidişatı yolunda tutmak için önemli olduğunu söylüyor. Kendim kişisel olarakda sürekli yapılacaklar listesi tutuyorum. Hatta şuanda çok sevdiğim rememberthemilk sitesini tavsiye edebilirim. Web üzerinde oldukça pratik yapılacaklar listeleri oluşturup,bunlara öncelik atayıp yayınlayabiliyorsunuz. Tabi bunu illa bir yazılım yoluyla yapmak zorunda değilsiniz. En güzel kayıt aracı hala bence defter kalem ikilisi. Mesela daha önceki çalıştığım firmada bunu proje içinde uygulardık. Öncelikle müşterinin isteklerine göre haftalık yapılacaklar listesi oluşturup herkes için bunu yayımlanırdı. Ardından proje yöneticimiz ile birlikte bunlara öncelik atardık ve önceliği en yüksek olan özellikleri geliştirmeye başlardık. Önceliği yüksek olan öğeler bitmeden düşük öncelikli öğelere geçmezdik. Bu şekilde önüimüzdeki işleri rahatça takip edebilirdik.Ayrıca müşteride şuanda hangi özellikler var, ve projenin genel gidişatını kolaylıkla öğrenebiliyordu. Liste dediğimiz şey çok abartlama gerek yok kısaca aşağıdaki gibi diyebiliriz.

    Visual Earth entegrasyonu yapılacak(Öncelik 1) Zoom out seçeneği eklenecek(Öncelik 2) NAnt bile build scripti yazılacak(Öncelik 3) Geliştirme makinası Ubuntu üzerine taşınacak(Öncelik 3)

Gördüğünüz gibi liste kısaca yukarıdaki gibi yapıya sahip.Kitapta listelerin sahip olması gereken temel özelliklerini sıralayarak açıklamış. Liste aşağıdaki özelliklere sahip olmalıdır.

    Herkes tarafından ulaşılabilir(Listeyi gizledikten sonra bir faydası yok) Önceliklendirilmiş(Yukarıda bahsettik) Zaman tahmini yapılmış(Projede tahmin sürelerinin geliştirilmesi için yapılaraklara zaman tahmini eklenmesi ) Canlı(Bir defa yaz kenara at değil, sürekli gelişen değişen) Ölçeklenebilir(“Performansı arttır” gibi bir öğe yerine “login ekranında giriş 5 saniyeden kısa olmalıdır”.) Hedef kitlesi belirli(Takımın yapılacaklar listesi ya da kişisel yapılacaklar listesi)

Teknik Lider

Bu kısımda projede bulunması gereken takım lideri,teknik lider gibi kişilerin rollerinden ve neler yapması gerektiğinden bahsediyor.Öncelikle teknik bilgisi yetersiz bir proje yöneticisiyle çalıştınız mı bilmiyorum fakat ben acı şekilde bunu tecrübe ettim. Böyle biriyle çalışmanın en büyük problemlerinden biri sizin geliştirdiğiniz yazılımın sorunlarından , teknik detayından çok fazla haberdar olmadığı için çoğu zaman gerçekçi olmayan planlar çıkarabiliyorlar. Onun için yeni bir özellik desteği eklemek 1 günü alabiliyor fakat işin içinde In Hohe und Art kann sich ein spielautomaten online Bonus allerdings von Casino zu Casino erheblich unterscheiden. olan siz oradaki problemi biliyorsunuz ve bunun bu sürede çıkarılamayacağını söyleyince muhtemelen şöyle bir cevap alıyorsunuz; “A tablosuna yeni bir alan ekleyelim bu problemi çözecektir” :) Bu arada konu ile alakalı değil fakat söylemeden geçemiycem, DB oriented insanlarla ya da proje yöneticisiyle çalışmanın en ilginç bulduğum yanlarından biride her problemin çözümünü bir tablo ile ya da tabloya bir alan eklemeyle çözmeleridir :). Tabi proje yöneticiniz yazılım hakkında çok iyi olan biriside olabilir. Fakat bu da problemi çözmeyecektir. Çünkü takım içinde olmadığı için sizin kod içindeki problemlerinizi bilmediği için aynı problemler devam edecektir. Bu yüzden kitaba kesinlikle katılıyorum.Proje içerisinde Takım Lideri ya da Teknik Lider bulunması gerekiyor. Böylelikle takımın problemlerini bilip onlara daha uygun çözümler ve daha uygun planlar çıkarabilir. Teknik Lider neler yapar kitapta şu şekilde belirtmiş.

    Müşterinin belirttiği önceliklerle takımın çalışmasının örtüşmesini sağlar Takımın çalışmasının üst yönetime ya da proje yöneticisine düzgün olarak sunar. Teknik konuları teknik olmayan insanlara iletir. Projede Teknik olmayan konuları takıma bildirir. Takım üyelerine yön çizer Projenin özellik listesini düzenler. Yapılacak özellikleri takım ile birlikte önceliklendirir Takımın dış etkenlerden rahatsız olmamasını sağlar

Hergün İşbirliği ve İletişim İçinde Olun

Bu kısımda takım olmanın en önemli unsurlarından olan iletişimden bahsetmiş. İletişimi arttırmak için özellikle günlük toplantıları anlatmış. Öncelikle neden iletişimi arttırmalıyız ona değilenim. Aynı problemleri tekrar çözmemek için,tekerleği tekrar icat etmemek için iletişim gerçekten önemli.İletişim; Takımda herkesin birbirinin yaptığı iş hakkında fikir sahibi olması, o işin başka kişiler tarafından yapıldıysa bilgilerinin paylaşılması, karşılaşılan hataların paylaşılması ve bu hatalar ile daha önceden karşılaşanların bilgilerini paylaşarak probleme daha hızlı çözüm üretmesini sağlar. Özellikle daha az bilgili takım elemanlarının bu konularda daha fazla bilgi ve tecrübeye sahip geliştiricilerden faydalanarak problemlere nasıl çözüm bulacağını anlaması ve takım olarak gelişmeyi arttırır. Ayrıca hergün takımın durumunu görerek projenin yolundan çıkmamasında önemli rol oynar.

Burda iletişimi sağlamak için kitap Scrum,XP gibi yöntemlerde kullanılan günlük toplantı yöntemini tavsiye ediyor. Ayakta toplantıların bir toplantı havasından çıkıp günlük bir aktivite olması için herzaman aynı yerde aynı saatte yapılmasını tavsiye ediyor. Burada toplantı deyince benim aklıma bitmek bilmeyen haftalık ya da aylık şirket toplantıları geliyor. Daha önceden bu tarz toplantılarda çok bulunmuştum açıkçası herkesin benim gibi bitsede kurtulsak modunda olduğunu görebiliyordum. Çünkü toplantı belli bir süre sonra gereksiz uzayıp çıkmaza giriyordu.Bazen kişiler arasındaki tartışmalara dönüşüyordu.Bu yüzden günlük ayakta toplantılar bu bakımdan oldukça verimli.Toplantının süresi 15 dakikayı geçemiyor. Herkes dün neler yapmış bugün neler yapacak onları anlatıyor. Ayrıca karşılaştığı problemler varsa onlardan bahsediyor. Bu şekilde problem ile daha önce karşılaşmış ya da çözümünü bilen biri toplantıdan sonra takım arkadaşına yardım ederek problemi daha hızlı çözmesini sağlıyor.Toplantıda tabi yaptığı işi anlatırken geliştirici işimin yarısını bitirdim diye yuvarlak cümlelerle değil dün login ekranını yaptım bugün şunları yapacağım diye daha açıklayıcı cümleler ile belirtiyor.

Kodunuzu Gözden Geçirin

Klasik adıyla Code Review. Sizinde başınıza mutlaka gelmiştir. Bir takımın içinde, diğer takım öğeleri tarafından yazılan kodun size tamamen yabancı hiçbirşey ifade etmediği durumlarla karşılaşmıştırsınız. Tabi bende karşılaştım. Başkasının yazdığı koda dokunmadığınız sürece problem yok fakat diğer takım arkadaşınızın başka bir projeye geçmesi, tatile çıkması, işten ayrılması vb.. gibi durumlarda kaçınılmaz son olarak kodu değiştirmek zorunda kaldığınızda asıl problem o zaman başlıyor demektir. Daha önce hiç görmediğiniz kod ile karşı karşılayısınız ne yapacaksınız kodun ne testi var, ne düzgün bir yapısı,okunaklı değil vs..İşte bu tarz problemlerle takım olarak çok fazla karşılaşmamak için kitap ve ben klasik adıyla Code Review yapmanızı şiddetle öneriyoruz :)

Yazılım geliştiren bir takımın bence iletişimi ve bilgiyi arttırma konusunda en efektif yöntemlerden biri. Ayrıca hataların bulunması ve problemlere daha çabuk çözüm bulunması için oldukça faydalı. Aslında çok basit bir işlem olmasına rağmen çoğu geliştirici ekibinde neden hala uygulanmıyor bir türlü anlamış değilim. Mantık çok basit geliştirdiğiniz bir özelliğin kodunu versiyon kontrol sistemine check in etmeden önce kodunuzu gözden geçirecek bir ya da birkaç takım üyesi bulun. Kodunuza bakıp fikirlerini söylesinler iyileştirme ya da hatalı bir özellik varsa bildirsinler ve ardından kodunuzu versiyon kontrol sistemine gönderin. Bu kadar basit. Ayrıca kodunuzu başka bir takım arkadaşınızla gözden geçirdiğinizde çözemediğiniz bir problem varsa ona anlatırken farklı bir perspektifle baktığınız için kafanızda büyük ihtimalle çözümü bulacaksınız.Buna Rubber Ducking deniyor.

Ayrıca tecrübeli elemanların acemi elemanlara kodları gözden geçirirken bilgi aktarması çok kolay.Özellikle Object Oriented,Design Patterns,Refactoring konularında bilgili deneyimli geliştiriciler kod gözden geçirmeleri sırasında bu bilgilerini takım üyelerine problemlemler üzerinde anlatıp takımın gelişmesine de katlı sağlarlar.Ayrıca gözden geçirme sırasında kodunuz karşıdaki tarafından anlaşılamıyorsa bu kodunuzu basitleştirmeniz gerektiğinin işaretidir.

Kod Değiştiği Zaman Uyarı Gönder

Bu kısımda versiyon kontrol sistemi gibi kodun herhangi bir yeri değiştiğinde gerekli kişilere uyarı mesajları halinde bunun bildirilmesini tavsiye ediyor.Özellikle kimin ne yaptığını izlemek için efektir bir yöntem olduğunu söylüyor.Bu konuda hiç tecrübem olmadığı için yorum yapamıyorum

Özet Liste

Yapılacaklar Listesi:

Herkes tarafından izlenebilir
Önceliklendirilmiş
Zaman tahmini yapılmış
Sürekli değişen

Teknik Lider:

Projenin özellik listesini yönetir
Developerların yaptığı işleri ve güncel durumlarını kontrol eder
Yapılacak özelliklere öncelik atamada yardımcı olur
Takımı dış etkilerden izole eder.

Günlük Toplantılar

Kısa tutulmalılar
Konular belirgin olmalı
Problemleri anlatın toplantıda çözmeye çalışmayın

Kod Gözden Geçirmeleri:

Küçük miktarda sık sık kodu gözden geçirin
Gözden geçiren sayısı bir ya da iki kişi olsun
Gözden geçirme yapılmadan kodu yayınlamayın

Code change notifications:

EMail ile değişiklikleri bildirin
Değiştirenin adını bildirin
Değişikliğin amacını yazın