Arda Çetinkaya Yazılım ve arada kendim ile ilgili karaladıklarım…

Bilgisayar ile oyun oynayanlar için “GodMode” çok tanıdık gelecektir. Bir çok oyunda hile olarak “GodMode On” yazdığımızda oyun daha bir eğlenceli oluyordu…

Windows 7 ,Vista ve Windows Server 2008’de da benzer bir tanrı modu mevcut. Tüm Windows sistem ayarlarına tek bir ekrandan ulaşabileceğiniz, yönetim amaçlı bir ekran bu “GodMode”…

Masaüstünde yeni bir klasör yaratıp,klasör ismine GodMode.{ED7BA470-8E54-465E-825C-99712043E01C} verdiğiniz zaman, klasörün “icon”u ve adı değişiyor ve tüm sistem ayarlarını kontrol edebileceğiniz bir ekrana artık sürekli ulaşabiliyorsunuz…Çok şık…


“User Story”, Scrum’da çok önemli kavramlardan bir tanesi. Aslında tüm yazılım geliştirme projelerinde bu kavram var. Ama farklı şekilde ele alındığından ya da gerekliliği ve önemi çok farkında olarak ele alınmadığından dolayı zaman zaman havada kalan bir kavram olabiliyor.

Genellikle çeşitli analizlerden sonra ortaya çıkan iş gereksinimlerinden(Business requirments),  fonksiyonel gereksinimler(Functional requirments) ortaya çıkartılıyor ve yapılacak iş(task-item) şeklinde ele alınıyor. Ama ne yazık ki çok da doğru bir şekilde “task” olarak ele alınmadığından dolayı(-ki bu noktada, kişisel olarak “task” olarak bir kavramın bu aşamada ele alınmasının doğru olduğuna inanmıyorum) gün sonunda sahipsiz, fazla bir şey ifade etmeyen, ya da ifade ettiği kavramın ürün açısından bir geçerliliği olmayan kavramlar ortaya çıkıyor. Geliştirme bittiğinde, çıkan ürünle bu “task”lar karşılaştırıldığında çok farklılıklar gözlemleniyor falan. Geliştirme sürecindeki en önemli sorunlardan biri sanırım da bu.

Bu noktada “User Story” kavramının çok iyi anlaşılıyor olması, fonksiyonel ihtiyaçları ortaya çıkarmada ve paylaşmada çok önemli. “User Story” basitçe; ürünü kullanan veya ürün sahibi için değerli olan ve anlam ifade eden fonksiyonel(?) özelliklerin belirtildiği ifadeler demek çok da yanlış olmaz sanırım. İfade yöntemi olarak bir çok kaynakta, belli formatlar da kartlar görebilirsiniz. Ama artık çokta tercih edilen bir yöntem olduğunu düşünmüyorum kendi tecrübelerimden dolayı. Pratikliğin önemli olduğu Agile yöntemlerde bu tarz kartlar hazırlamak falan sıkıcı olabilir. “User Story”leri postitler ile ifade ediyor olmak en kolay yöntem.Ki “User Story”lerin herkes tarafından kolayca ulaşılabilecek olması postitlerin sağa sola yapıştırılabiliyor olmasından dolayı da postitlere artı puan katan bir nokta.(: (Sponsor:Post-It)

Fonksiyonel özelliklerin ifade yöntemi dedik…Peki ne kadar ayrıntılı olacak bu ifade? Çok fazla değil…Ürün sahibi veya kullanıcı acısından değeri olan tek bir anlamlı cümle yeterli olacaktır.

As a user, I want to post a comment to your blog with my Facebook account,so that I do not have to create another account in your blog.

Yukarıdaki örnekteki gibi tek cümle olarak ifade ediliyor olması, yapılacak işlerin daha net ortaya çıkmasında faydalı olacaktır. “As a <rol>, I want to <amaç>, so <sebep>” şeklinde bir format Scrum’ı ortaya çıkaran kişilerin “User Story” için gösterdiği bir format. Amaç ve sebep ilişkisi açısından ele alındığında da ne kadar doğru bir ifade şekli olduğunu zaten kendi de gösteriyor. Burada bir başka önemli nokta “User Story”lerin herkes için aynı şeyi ifade ediyor olması gerekliliği. Takımdaki kişiler için farklı şeyler ifade ediyorsa bir “User Story”, onun için çok da anlamlı bir “User Story” demek doğru olmayacaktır.

Yukarıdaki örnekteki <rol>,<amaç> ve <sebep> kavramlarının netliği “User Story”nin anlamını güçlendirecektir. Buradaki;

  • Rol: Ürün sahibi,ürün kullanıcısı,geliştirici,testçi gibi proje ve takım içerisinde olan herkes olabilir.
  • Amaç: “User Story”nin ifade etmeye çalıştığı, ürün özelliği ya da fonksiyonu.
  • Sebep: Yapılacak ya da geliştirilecek olan özelliğin sebebi.

Başarılı ve doğru bir “User Story”nin dayandığı bir kaç özellik var. Tabi ki bunlar kesin ve doğru şeyler değil ama bir çok kaynakta benzer şeylerden bahsedildiğini göreceksiniz.”User Story”ler birbirinden olabildiğince bağımsız olmalıdır. Bu bir “User Story”nin net olarak anlaşılması için en önemli faktördür. Bazı ürün fonksiyonları geniş bir ifadeye sahip olabilir, bunları yapabildiğimiz kadar anlamlı parçalara ayırmak önemlidir.

“User Story”ler kural babında kesinlik ifade etmemelidir. Takım tarafından tartışılabilir ve geliştirilebilir. Zamanla değişecek ihtiyaçlardan dolayı bu yaklaşımda yazılması, değişen ihtiyaçları daha iyi görmede yardımcı olacaktır.Aynı zamanda “User Story”nin farklı bakış açıları ile doğru bir şey ifade etmesi de bu yolla olacaktır.”User Story”ler yukarıda da bir çok kere belirttiğim üzere değerli ve anlamlı olmalıdır. Açıkcası bence en önemli özellik bu.

“User Story”ler tahmin edilebilir olmalıdır. Bu tahminin gerçekçiliğinden çok, “User Story”lerden çıkacak “task”ların tahmininin gerçekliği daha önemlidir. Direk “User Story”e tahmini bir puan vermekten çok, tahmin sırasında oluşturulacak “task”lara tahmini bir puan vermek ve bunların toplamı ile “User Story”nin tahmini puanının ortaya çıkmasında daha doğru bir yol olduğunu söyleyebilirim.Bu konuda çok sorun yaşadık ama sonradan ayırdığımız “task”lara verdiğimiz tahmini zamanlar puanlarının daha anlamlı olduğu kanısına varmıştık.

“User Story”ler küçük ama anlamlı olmalıdır. Ne kadar büyük olursa, karmaşıklığı o kadar artar,anlamı o kadar derinleşir. Çok fazla küçük olursa da ifade etmeye çalıştığı kavram o kadar silik olur.

Şimdilik “User Story”ler ile ilgili olarak tecrübelerime göre bunları söyleyebilirim. Önceki yazılarımda da söylediğim gibi bu konuda ciddi bir bilgi paylaşımına girmek istiyorum, ilgileniyorsanız mutlaka fikirlerinizi, sorularınızı, eleştirilerinizi paylaşın.

Agile yazılım geliştirme metodlarından Scrum’da, geliştirme sürecinde, çıkacak ürünün özelliklerini ortaya çıkarabilmek ve bunları iyi analiz edebilmek çok önemli. X adında bir ürün geliştireceğimizi düşünelim. Belli bir amaç için geliştirdiğimize göre, bu amaç(lar) doğrultusunda ürünümüzün belli özellikleri olacaktır. Bu özelliklerin uygulanma açısından da çeşitli fonksiyonlar olacaktır. Tabi bütün bunlar son kullanıcı ya da ürün sahibinin ihtiyaçları ve üründe gerçekleştirmek istediği işlerden(scope) oluşacaktır.

Scrum’da bunların listesine “Product Backlog” deniyor. Scrum’ın uygulanabilmesi için olmazsa olmaz bir kavram bu “Product Backlog”. “Product Backlog” listesi oluşturulurken, analiz sonuçlarından ve daha önceki projelerdeki tecrübelerden yararlanılır. Bu liste sadece yapılacak ürünün özelliklerini içermek zorunda değildir. Ürünün özellikleri ile ilgili, önceki tecrübelerden ortaya çıkmış ve ürünü geliştirirken etki edebilecek kavramlarda bu listeye alınmalıdır. Teknik olarak geliştirme sürecinde direk olarak bir şey ifade etmeyen ama dolaylı olarak ürünün genelinde etki edebilecek kavramlar da bu liste dahilinde ele alınabilir.

Bu liste oluşturulurken, herkes katkıda bulunabilir. Geliştiriciden, ürün sahibine, proje yöneticisinden, test ekibine kadar geniş bir kesim bu listenin oluşmasını sağlar. Ne kadar çok katkı olursa o kadar sağlıklı bir “Product Backlog” çıkacaktır.Tabi herkesin katkı yapıyor olması, her katkının da bu listeye dahil olacağı anlamına gelmiyor. Tabi ki listeyi oluştururken de “scope”un dışına çıkmamak gerekiyor.

Bu listenin en önemli ve Scrum tarafından anlam taşıyan bir diğer özelliği listedeki maddelerin bir öncelik(priority) sırasına sahip olması. Bu öncelik sırası, sadece ürün sahibi(product owner) tarafından belirlenmelidir. Bunun nedeni az önce de kullandığım “scope” kavramının dışına çıkılmasını engellemektir.

Şimdilik bu kadar, bu konuda her türlü fikrinizi,düşüncenizi veya sorunuzu bekliyorum…

Bir önceki yazımda WPF’de kontrol içerisindeki kontrollerde oluşan “event” sorunundan bahsetmiştim. Aslında sorun değil, WPF’deki “event” yaklaşımının biraz farklılaştığını belirtmeye çalışmıştım. Bu yazıda biraz daha derinlere girip, WPF’deki “Routed Events”‘den bahsetmeye çalışacağım.

WPF, kullanıcı deneyiminin uygulamalarda daha rahat bir şekilde uygulanmasını amaçlıyordu hatırlarsanız. WPF’in ortaya ilk çıktığından beri Microsoft’un altını çizdiği nokta bu yönde. Bu bağlamda, standart bilgisayar uygulamalarında ki standart arayüzler yerine kullanıcının çok daha kolay kullanabileceği bir arayüz sunmak ve bu arayüz ile sunulan bilgileri de daha anlamlı bir görsellikte sunarak kullanıcı deneyimini uygulamalara katmak WPF’in ilerlediği yollardan bir tanesi diyebiliriz. Bu yaklaşımdan dolayı, WPF ile beraber alıştığımız kullanıcı kontrollerinden farklı bir yapı karşımıza çıkıyor. Tıkladığımız düğmeler WPF ile beraber daha farklı amaçlar için kullanılabilir hale geliyor. Ya da bir çok elemandan, seçim yapabileceğimiz kullanıcı kontrolleri içerik olarak daha anlamlı bilgiler içermeye başlıyor.

Mesela bir düğme(button)nin içine resim koyarak, düğmenin görselliğine farklı anlamlar yükleyebiliyoruz.Bu çok basit bir örnek oldu gerçi ama demek istediğim, WPF’de kullanıcı kontrollerini, farklılaştırarak zenginleştirebiliyoruz. Kontrolleri iç içe kullanabiliyoruz. Bir “button”(düğme) içine “image”(resim) kontrollü koymak gibi. Katmanlı bir kullanıcı kontrolü yapısı var demek biraz daha netleştirebilir belki.

“Routed Events” kavramı da bu yapıdan dolayı ortaya çıkıyor. Yukarıda bahsettiğim kontroller üzerinden örneklendirmek daha anlaşılır olacak sanırım. Aşağıdaki uyduruk resimde(:)) bir “button” içinde “image” var.

Şimdi “button”a tıklandığı zaman “click” olayı oluşur bildiğiniz üzere. Ve tıklandığı zaman ne olmasını istiyorsanız bu olaya(event) denk gelen metodda ilgili kodu yazarsınız. “button” tıklandığı zaman ne oluyorsa, aynı işlem üzerinde “image” kontrolü olan “button”a tıklandığında da olmalı. Tıklanan alan “image” kontrolüne denk geliyorsa tıklama işleminin “button” tarafından da anlaşılıyor olması lazım. Bundan dolayı “image” üzerinde bazı işlemlerin, “image”ı içeren kontroller tarafından da algılanabiliyor olması lazım. WPF bu işlemi “routed events” kavramı ile gerçekleştiriyor.Özetle WPF’de bir “event” başka elemanlara yönlendirilebiliyor.

Bir önceki yazıda gerçekleşen olayın sebebi bu yani. WPF’de bir uygulama geliştirirken, “routed events” kavramını kendi geliştireceğiniz kontrollerde kullanmanız kaçınılmaz olacaktır. İlerleyen yazılarda bununla ilgili çok basit bir örnek göstermeye çalışıyor olacağım…Şimdilik bu kadar.

Not: “button” ve “image” anlaşılır bir örnek olması açısından kullandığım kavramlar. WPF’deki mevcut tüm yapılar için “routed events” kavramı geçerlidir.

, ,

Geçen gün bir arkadaşımın WPF(Windows Presentation Foundation)’den çektiği dertleri Twitter’dan gördüm ve benzer bir sorunu yaşadığım için şaşkınlığını çok iyi anladım. WPF kavram olarak çok güzel şeyler vaad ediyor olsa da, açıkcası tam olarak oturmuş bir yapı olduğuna inanmıyorum. İlk çıktığı zamandan beri kendimce küçük uğraşlar ile WPF’i elimden geldiğince takip etmeye öğrenmeye çalıştım,çalışıyorum da. Diğer .NET Framework yapıları ile kıyaslandığında farklılıkları ve değişiklikler ciddi anlamda uğraştırıyor.Neyse çok dağıtmadan konuyu, özüne dönelim.

WPF’de “control” yapısı, ASP.NET ve Windows yapısına göre biraz daha farklı. Bu farklara değinmek şimdi uzayacağından sadece farklı olduğunun altını çizmek yeterli olacaktır şu aşamada.

Sorunumuz ne peki? TabControl içinde kullandığımız Listbox,Combobox gibi yapılarda “SelectionChanged” event’i(olayı) çalıştığı zaman tabcontrol’ün de “SelectionChanged” event’i çalışmakta.Bunun nedenlerini inceleyerek sorunu çözmek, WPF’i anlamak adına daha faydalı olacağından olayın en temeline inerek çözümü sunmaya çalışacağım.

WPF’de “Selector” diye bir sınıf var. Listbox,Combobox gibi seçme işleminin yapılabileceği kullanıcı kontrolleri bu sınıftan türemekte.  “Select” operasyonunun yapılacağı kontrollerin “Selector”dan türemesi kavram olarak bakıldığında çok normal. WPF’de TabControl diye bildiğimiz sekmeli bir yapı sunan kontrolde WPF’de “Selector”dan türemekte.Yani ListBox,Combobox ve TabControl aynı kategoride diyebiliriz daha basitçe.Bu kontrollerin “SelectionChanged” event’i Selector sınıfından gelmekte ve dinlenmekte. TabControl’ün veya Combobox’ın ne yazık ki kendilerine özgü düzenlenmiş bir SelectionChanged event’i yok.Bundan dolayı “Selector.SelectionChanged” event’i tetiklendiği zaman Selector sınıfından türeyen sınıflarda bu event’i kontrol etmeye çalıştıklarında başarılı olacaklardır.Yani daha açık bir şekilde; TabControl’ün SelectionChanged event’inde çalışan bir metodu olduğunu varsayalım:

81 protected void TabControl1_SelectionChanged(object sender, SelectionChangedEventArgs e)

82 {

83 //tab seçildi

84 }

Aynı şekilde Tabcontrol’ün içindeki bir ComboBox’ın da aynı event’de çalışacak bir metodu olduğunu varsayalım:

86 protected void Combobox1_SelectionChanged(object sender, SelectionChangedEventArgs e)

87 {

88 //combox’da seçildi

89 }

Uygulama çalıştığı zaman ComboBox’dan bir seçim yaptığınızda, ComboBox’ı içeren kontrolün(TabControl oluyor bu durumda) de SelectionChanged olduğu zaman çalışacak metod da çalışacaktır…Çok ilginç değil mi? Bunun nedeni yukarıdaki kısa açıklama. Ama asıl nedeni WPF’de ki event mekanizması.WPF ile beraber Routed Events diye bir kavram hayatımıza giriyor.Bir sonraki yazımda bunun ne olduğunu anlatmaya çalışacağım, çünkü WPF ile uğraşanlar için oldukça önemli bir şey olduğuna inanıyorum.Neyse sorunumuza dönelim…Şimdi en son combobox’ı seçmiştik ve tab kontrolününde metodu çalışmıştı. Bunu istemiyoruz tabi ki…Peki ne yapacağız…

Event argümanlarının(e parametresi oluyor metoddaki) “Handled” diye bir özelliği var. Bu özelliği “true” olarak değiştirdiğiniz zaman oluşan olayı(event) yakalamış olduğumuzu belirtiyoruz.

86 protected void Combobox1_SelectionChanged(object sender, SelectionChangedEventArgs e)

87 {

88 //combox’da seçildi

89 e.Handled = true;

90 }

Bu sayede TabControl’ün event’i çalışmamış oluyor…WPF ile geliştirme yaparken, bu tarz sorunları aslında sorun olarak değilde, değişiklik olarak algılamak gerekiyor sanırım.Neyse şimdilik bu kadar…Her türlü soru,sorun,düşünce fikir paylaşımına açığım,bekliyorum…(:

, ,