Çevik Süreçler Neden Dikiş Tutturamadı

Çevik süreçlerin tam olarak ne olduğunu kavramamış, çevik süreçler ile bir proje uygulamamış, scrum yaparak çevik olduğunu ve çevik süreçlerin bir işe yaramadığını zanneden şahısların “agile is dead” naralarını unutmadık. Ben de çevik süreçler öldü diyorum, lakin ekliyorum: “yaşasın çevik süreçler”. Çevik süreçlerin yıldızlarının bundan sonra nasıl parlayacaklarını ve tam anlamıyla yazılım geliştirme süreçlerine hakim olacaklarını kendi yazılımcı perspektifimden sizinle paylaşmaya çalışacağım.

Bir yazılım sistemi belli bir büyüklüğe ulaştıktan sonra, kendi dinamiklerini oluşturarak, yeni özellikler eklenmek suretiyle geliştirilmesini engeller hale gelir. Bunun başlıca sebebi, mevcut mimarinin yeni özellikleri taşıyacak yapıda olmamasıdır. Bunu bilen yazılımcılar iki nokta arasındaki en kısa mesafeyi seçmek yerine, en az dirençle karşılacakları patikayı yeğlerler. Bunun neye sebebiyet verdiğini çok iyi biliyoruz: teknik borç! Burada yazılımcının büyük oranda suçu olmadığını düşünüyorum. Daha ziyade yazılımdan bihaber yöneticiler zaman baskısı oluşturarak, işi aceleye getirmektedirler ve aslında başarısızlığın temelini ilk saniyeden itibaren atmaktadırlar. Bu duruma yazılımcılar tepki vermeyerek ve kimsenin etlisine, sütlüsüne karışmayarak ortak olmaktadırlar. Lakin şöyle yöneticilerin karşılarında ağız birliği yaparak, dik durabilseler ve “madem bu işi biz yapıyoruz, o zaman ne zaman biteceğine de biz karar veririz” diyebilseler, çok daha güzel işler ortaya koyabilecekler.

Yazılımda bu sorun ile başa çıkmanın tek bir yolu mevcut, o da refactoring olarak adlandırılan kodun yeniden yapılandırılmasıdır. Teoride her yazılımcının yeniden yapılandırmanın ne anlama geldiğini bildiğini düşünebiliriz. Lakin pratik açıdan baktığımızda, yeniden yapılandırma işleminin nasıl yapıldığı konusuna çok az sayıda yazılımcı hakimdir. Bunun da başlıca sebebi, yazılım testleri üzerinde olan hakimiyetsizliktir.

Refactoring tek başına yapılması mümkün olmayan bir işlemdir. Yapılan her değişiklik bir yan etki doğurabileceğinden, bu etkinin tespit edilebilmesi zaruridir. Bu kontrolü bir yazılımcının elden yapması mümkün değildir. Bu sebepten dolayı burada bir otomasyon ihtiyacı doğmaktadır. İhtiyaç duyulan kapsama alanına sahip olduğumuzu farz ettiğimizde, otomatik çalışan testler refactoring esnasında oluşan tüm yan etkileri tespit etmeyi mümkün kılacaklardır. Özetleyecek olursak, aslında yazılım sisteminin sürekli gelişimi için ihtiyaç duyduklarımız yeniden yapılandırma, test yazılımı ve test otomasyonudur. İşte çevik süreçlerin temelini de bunlar oluşturmaktadır. Eğer sürekli müşteri gereksinimlerini koda dökebiliyor ve mevcut sistemi genişletebiliyorsanız, çeviksiniz! aksi tektirde yazılımcılık oynuyorsunuz!

Çevik süreçler bünyesinde yer alan çevik metotların ana amacı yazılımda sürdürülebilirliği hedefliyor olmalarıdır. Burada sürdürülebilirlik terimini teknik açıdan ele almamız gerekmektedir. Sürdürülebilirlik bir yönetici için başka, bir yazılımcı için daha başka, bir patron için çok daha başka bir anlam ifade etmektedir. Ama doğru olan yaklaşım hangisidir? Şüphesiz herkes kendince doğru yaklaşım içindedir, çünkü beklentiler değişiktir. Lakin tekrar altını çizerek sormak istiyorum, teknik olarak sürdürülebilirlik ne anlama gelmektedir? Bunun cevabını verebilmek için öncelikle işin müşteri kısmını incelememiz gerekiyor.

Bir yazılım sistemi müşteri gereksinimleri doğrultusunda şekillenir. Yazılımcı olarak nihai amacımız, müşteri gereksinimlerini tatmin edecek bir sistem oraya koymaktır. Bu yüzden doğal olarak müşteriye kulak vermemiz ve ne istediğini iyi anlamamız gerekmektedir. Lakin müşteri ne istediğini tam olarak bilmekte midir? Ne yazık ki bu sorunun cevabı hayıdır. Burada yazılımcı olarak bizim için iki sıkıntı oluşmaktadır. Birincisi nasıl bir sistem oluşturmamız gerektiği sorusudur, ikincisi bu sistemin mimarisinin nasıl olması gerektiğidir. Bu iki sorunun da cevabını düşünerek, bulmamız mümkün değildir. O yüzden bir an önce kolları sıvıyarak, müşteriye yarım yamalak dile getirdiği gereksinimleri için kısa bir zaman dilimi sonunda bir şeyler göstermemiz gerekmektedir ki müşteri ne istediğine dair fikir üretmeye başlayabilsin. Bu yüzden çevik süreçlerde bir ya da iki haftalık iterasyonlar sonunda müşteriye mutlaka tespit edilen miktardaki özelliğin çalışır durumda olduğu sistemler sunulur. Bu prototipler müşteriden alınan geribildirimler doğrultusunda onun kullanacağı ürün olana kadar geliştirilir. Lakin burada tekrar sürdürülebilirlik konusuna değinmemiz gerekmektedir. Teknik olarak bu nasıl sağlanabilir? Bunun iki yöntemi mevcuttur: Teknik borç ve teslimiyet ya da kararlılık ile uygulanan “yap/boz” mentalitesi.

Eğer bir bina yapımı söz konusu ise, atılması gereken temelin ve uygulanmak istenen mimarinin bilinmesi gerekmektedir. Bu değişmez iki parametre yapılan binanın kaderidir. Eğer inşaat mühendisleri ve mimarlar yazılım yapmaya başlasalardı, hiç zorluk çekmeden bu işe adapte olabilirlerdi, çünkü günümüzde de yazılım bir bina inşaatı gibi ele alınmaktadır. Durum böyle olduğu için yazılım projelerinin çok büyük bir kısmı belli bir zaman sonra çıkmaza girerek, hem yazılım sistemini oluşturanları hem de müşterisini zorda bırakmaktadırlar.

Tekrar teknik sürdürülebilirlik sorusuna geri dönelim. Teknik sürdürüleiblirliğin bedeli ne yazık ki ağırdır. Öncelikle yazılımla uğraşan herkesin bu bedeli maddi ve manevi olarak ödemeye hazır olması gerekmektedir. Maddi açıdan baktığımızda yöneticilerin sürdürülebilirliği sağlamak adına daha fazla zamana ihtiyaç duyulduğunu ve bunun maliyeti artıracağını anlamaları, manevi açıdan baktığımızda yazılım mühendislerinin işin çıkmaza girdiğinde radikal kararlar vererek, refactoring teknikleri yöntemleri ile mevcudiyeti yeniden şekillendirme iradesine sahip olmaları gerektiğini görmekteyiz.

Günümüzde yapılan yazılımı yirmi sene önceki şekli ile kıyasladığımızda, aslında kafalarda fazla bir şeylerin değişmediğini görebilmekteyiz. Çoğu yazılım projesi yirmi sene önceki kafa yapısı (mindset) ile uygulanmaktadır. Yirmi sene önce aktif olarak hayatımıza giren çevik metotlar ihtiyaç duyulan dönüşümü sağlayamadılar. Bunun nedeni ne olabilir? Çevik süreçler performans gösterebilmek için çok radikal değişimlere ihtiyaç duymaktadırlar. Bu programcıların çalışma tarzlarından başlayarak, firmanın sahip olduğu yazılım geliştirme kültürüne kadar uzanana bir alanı kapsamaktadır.

Çevik süreçler programcı perspektifinden bakıldığında test güdümlü yazılım gibi radikal bir metodun uygulanmasını talep etmektedir. Yazılım birimlerini test etme konusunda pek kafa yormamış ve bu konuda tecrübesi olmayan bir yazılımcıdan test yazarak, yazılıma devam etmesini istemek, bir cobol yazılımcısına bugünden yarına nesne tabanlı program yazdırmaya çalışmak gibi birşeydir. Nitekim ikibinli yılların başlarında görev başında olan yazılımcıların bu fikri benimsemeleri mümkün olmadı. Onlar hep testlerin yazılımın en sonunda uygulanan bir aktivite olarak gördüler. Her zaman angarya olarak görülmüş test yazma olayının birden bire gündemin en başına oturarak, tüm gidişata yön verme fikrine o jenerasyon ne yazık ki adapte olamadı. Tekrar hatırlamakta fayda görüyorum. çevik olabilmeniz için yani müşteri gereksinimlerine her daim yazılım ile karşılık verebilmeniz için yeniden yapılandırma yapmak zorundasınız. Test olmadan yeniden yapılandırma yapılamaz. Bu yüzden çevik süreçlerin en temelinde bu iki prensip yatmaktadır: yeniden yapılandırma ve testler. Olay sadece test güdümlü yazılım ile bitmiyordu. Eşli programlama, sürekli entegatasyon, iterasyon bazlı yazılım gibi birçok çevik süreç metodu mevcut yazılım süreçlerini yer yer tersine çevirdiğinden dolayı, bu durum yazılımcılara sudan çıkmış balık hissi yaşatmakta ve adaptasyonu zorlaştırmaktaydı.

O dönemin yazılım sektöründe çalışanlarını şelale (waterfall) yazılım süreçlerinden geldiklerini unutmamamız gerekmektedir. O zamanın yazılım ekipleri müşteri gereksinimlerini en ince detayına kadar anladıktan ve kağıda döktükten sonra yazılım yapmaya başlarlardı. Burada bir senelik bir ön çalışma ve akabında yine birkaç sene sürebilen yazılım geliştirme sürecinden bahetmekteyiz. O gün olsun, bugün olsun yazılım projelerinin başarısız olmalarının ana sebeplerinden birisi ne yazık ki budur. Müşteri gereksinimleri doğrultusunda bir yazılım sistemine ihiyaç duyar. Müşterinin bu gereksinimleri piyasa şartları ile günlük bazda bile değişime uğrayabilirken, şelale yöntemleri ile birkaç sene kapalı kapılar arkasında yapılan yazılımın, bu zaman dilimi sonunda müşteri gereksinimlerine ne kadar az hitap edebilme potansiyeline sahip olduğunu görebilmekteyiz. Nitekim yazılım projelerindeki başarısızlık, müşteri gereksinimlerinin ne oranda karşılık göremediği ile çok yakından bağlantılı.

Hala ikibinli yılların başlarındayız ve çevik süreçlerin var olma savaşını yakından inceliyoruz. Şimdi o zamanlar yazılımın nasıl yapıldığını ve uygulanan mimarileri yakından inceleyerek, çevik süreçlerin neden tutunamadığını görmeye devam edelim.

İkibinli yılların başlarında Java programlama dili sahip olduğu ekosistemi ile tüm yazılım camiasına hakim olmaya başladı. O zamanlar EJB (Enterprise Java Beans) ile uygulama sunucularında yazılım yapanlar çok iyi hatırlayacaklardır. Tarih hep tekerrürden ibarettir, lakin umarım o günleri hiçbir yazılımcı tekrar yaşamak zorunda kalmaz. O devrin yazılım yöntemleri, araç ve gereçleri çevik süreçler için hazır değildi. Siz ne kadar iyi niyetli de olsanız ve test güdümlü yazılım ile birim testleri yazsanız bile, entegrasyon, onay/kabul testleri ve benzeri testlerin otomatik çalıştırılmaları onlarca ya da yüzlerce dakikanızı almaktaydı. Çok küçük bir değişilik yaptığınızı düşünün. Uygulamanın tekrar paketlenerek, uygulama sunucusunda çalışır hale gelmesi en az on dakikanıza mal olmaktaydı. Bunu çok defa yaşamış bir programcıyım. Çeviklik geribildirimle doğrudan orantılıdır. Yaptığınız şey size ne kadar hızlı geribildirim sağlarsa, o hızda değişilik yapabilirsiniz. Çevik olabilmek için yeniden yapılandırmamız gerekiyor. Bunun için testlerin sağladığı geribildirime ihtiyacımız var. Aynı şekilde sürekli entagrasyon yaparak, sistemin hangi derecede entegre olduğu geribildirimine ihtiyaç duymaktayız. Tüm çevik metotlar geribildirim prensibine dayanmaktadır. Geribildirim sağlanmadan, yaptığımız işin neresinde olduğunu anlamamız mümkün değildir. Geribildirim alma süresinin uzaması, bu o oranda çeviklikten uzaklaşma anlamına gelmektedir. Nitekim uygulama sunucularından kaynaklanan sebeplerden dolayı çok zaman alan test otomasyonu ilerleyebilmek adına devre dışı bırakılmak zorunda kalındı. O devrin EJB projelerine göz attığımız taktirde ya hiç ya da çok çok az oranda test koduna sahip olduğunu görebiliriz. Aynı durum bugün yapılan projeler için bile geçerlidir. Birçok güncel projede bir tane bile test metodu bulunmaması hiç şaşırtıcı değildir. Projelerin neden sürdürülebilir olmadıklarını ortadadır.

İkibin onlara kadar uygulanan yazılım prensip ve mimarileri de ne yazık ki çevik süreçler için gerekli ortamı oluşturamadı. Bahsetmiş olduğum zaman diliminde monolitler revaçtaydı. Durumun bugün bile değişik olduğu söylenemez. Trendin ama microservice mimarileri ile değiştiğine şahit olmaktayız. Peki bir monolit çevik süreçler ile geliştirilemez anlamına mı gelmektedir bu? Bu monolitin büyüklüğü ve bünyesinde barındırdığı kod kalitesi ile doğrudan ilişkili bir durum.

Çevik süreçler ile bir monoliti geliştirmek mümkün. Ama bu ne yazık ki belli bir büyüklüğe kadar sağlanabilir. O kritik büyüklüğe erişildikten sonra, sistemin küçük ve birbirinden bağımsız parçalardan oluşuyor ve geliştirilebiliyor olması gerekmektedir. Yani burada modüler bir yapıya ihtiyaç duyulmaktadır. Lakin bir monolit ne kadar modüler bir yapıda da olsa, tek bir parça olarak entegre edilmesi gerekmektedir. Burada yine test otomasyonu sorunları baş göstermektedir. Bunun yanı sıra entegrasyon süreleri uzamakta ve hızlıca yapılması gereken değişiklikler zaman almakta ve çeviklikten ne yazık ki ödün verilmesi zazuri bir hale gelmektedir. Tekrar hatırlayalım: hızlı bir şekilde geribildirim alınamayan ortamlarda çevik olunması imkansızdır.

Çevik bir yazılım ürünü yani her yeni müşteri gereksnimi ile yeniden yapılandırılabilen ve sürekli değişiklik ile başedebilen bir yazılım sistemi için belli başlı yazılım prensiplerinin, tasarım şablonlarının ve yazılım mimarilerinin uygulanması zaruridir. En basit hali ile clean code, solid prensipleri ve modüler bir mimariye ihtiyaç duyulmaktadır. Bunların uygulandığı bir proje test kültürü ile birleştiğinde her yeni müşteri gereksnimi ile hamur gibi yoğrulabilen yazılım ürünleri ortaya çıkamaktadır. Ama günümüzde bile birçok projede test kodunu bir yana bırakın clean code ya da solid prensiplerinden eser bile bulmak mümkün değildir. Testler olmadığından dolayı programcılar artık binlerce satırdan oluşan sınıfları değiştirmeye korkar olmuşlardır. Bu korkunun mevcut olduğu bir yerde nasıl yeni müşteri gereksinimleri hayat bulabilir?

Teknik açıdan baktığımızda, birçok sebepten dolayı çevik süreçlerin uygulanabilir olmadıklarını ve bu yüzden bir zaman sonra terk edildiklerini görebilmekteyiz. Lakin bunu tümüyle teknik sorunlarla ilişkilendirmek doğru değildir. Bunun yanı sıra firmalarda oluşan yazılım geliştirme kültürlerini ve organizasyonel yapıları da yakından incelememiz gerekmektedir.

Zaman içinde, çevik süreçlerin popülerliğinden de istifade edilerek benim fake agile olarak tabir ettiğim ve yazılımda çevikliği ima eden ama bunu sağlamaktan çok uzak sözde çevik süreçler oluştu. Bunların başında scrum geliyor. Scrum yakından incelendiğinde, aslında yakından, uzaktan çeviklik ile hiçbir alakası olmayan bir şey olduğu görülmektedir. Scrum ne çeviklik namına bir çevik metot ihtiva etmektedir ne de scrum ile çevik bir yazılım ürünü geliştirmek mümkündür. Çevik olmak için çevik metotlara ihtiyaç duyulmaktadır. Bunlar teknik anlamda yazılımcılar tarafından uygulanan metotlardır. Test güdümlü yazılım ya da eşli programlama gibi çevik metotları sadece yazılımcılar uygulayabilirler. Tüm çevik metotlar yazılımcılar için ve onların çevik hareket edebilmeleri için oluşturulmuşlardır. O yüzden çevik süreçler yardımı ile yazılım yapıyoruz denildiğinde, incelenmesi gereken nokta, çevik metotların ne oranda yazılımcılar tarafından yaşanıyor olduklarıdır.

Scrum ve benzeri yapılar ne yazık ki extreme programming gibi gerçek çevik metotların önüne geçtiler ve organizasyonlara çevik oldukları hissini verdiler. Kendini iyi hissetmekten öteye götüremeyen bu yaklaşımlar yazılım yapanların “çevik çalışıyor olmamıza rağmen, gerekli performansı alamıyoruz” söylenimlerine yol açtılar. Scrum ve benzeri yapılar ne yazık ki gerçek çevik süreçlerin adlarını karaladılar ve diskredite olmalarına sebep oldular. Bugün baktığınızda çevik olmayan bir yazılım ekibi bulamazsınız. Herkes scrum yapıyor ve herkes çevik. Ama ortaya çıkan yazılım ürünlerine göz attığımızda, hepsinin aynı dertlere sahip olduklarını ve aslında müşteri gereksnimlerine cevap veremeyecek yapıda, teknik ve mimarı açıdan tükenmiş olduklarını görmekteyiz.

Çevik süreçlerin önünü kapatan diğer bir durumda, yazılım ekiplerinin organizasyon yapısı olmuştur. Klasik bir yazılım ekibinde yazılımcı, testçi, analizci, sürümcü, proje yöneticisi gibi rolleri görmek mümkündür. Bir fabrika bandında üretim için uygun olan bu rol bazlı kadrolaşma, yazılım için ne yazık ki büyük sorular doğurmaktadır. Çevik süreçler yazılım, test, analiz, sürüm ve canlı işletme sorumluluğunu (production) yazılım ekibini oluşturan yazılımcılarda görmektedir. Yazılımcılar yazılım ile ilgili her şeyi yapamazlar mantığı doğru değildir. Mühendislik altyapısına sahip bu kişilerin günümüzde sadece kod yazmak için uygun olduklarını düşünmek en kibar ifadeyle onlara yapılan haksızlıktır. Nitekim Google tarafından uygulanan SRE (Site Reliability Engineering) ve DevOps gibi akımlara baktığımızda, yazılım ekibinin yazılım için gerekli tüm işlevleri yerine getirdiklerini görmekteyiz. Yazılımın, testin, analizin ve sürümün ayrı ekipler tarafından yapıldığı ortamlarda, çevik süreç faydalı olamamaktadır. Bu tür ayrıştırıcı organizasyonel yapılar olduğu sürece, çevik yazılım yapmak ne yazık ki mümkün değildir.

Yazılımda teknik sürdürülebilirlik için gerekli etkenleri ele almaya çalıştım. İsmi illa çevik süreç olmak zorunda değil. Lakin sürdürülebilirlik için atılması gereken somut adımlar var. Yazılımcının ana görevi sadece kod yazmak değildir. Mevcut organizasyonel yapılar bunun doğru olduğu fikrini savunsalar da teknik sürdürülebilirlik için yazılımcılara daha fazla sorumluluk verilmesi gerekmektedir. Yeni gereksinimlerin ivedilikle yazılım ürününe entegre edilebilmeleri için kodun her daim hamur gibi yoğrulabilmesi gerektirmektedir. Bunu sadece ve sadece yazılımcılar yapabilirler. Bunun için yüksek seviyede teknik beceriye ihiyaç duyulmaktadır. Bu da mühendisliğin hakkını verebilen yazılımcılarla mümkün olabilecek bir iştir.

Buraya kadar bahsetmiş olduğum nedenlerden dolayı çevik süreçler ne yazık ki hak ettikleri yere gelemediler ve haksız yere işe yaramaz damgasını gördüler. Ama ben bu durumun değişme sürecine girdiği düşüncesindeyim. Çevik süreçlerin işlemesini engelleyen unsurların yavaş yavaş kaybolmaya başladıklarına şahit olduğumuz bir dönemden geçiyoruz. Bu unsurlardan bazılarını yakından inceleyelim.

Artık günümüzde monolitlerin terk edilmeye yüz tutmuş bir mamarı türü olduğunu görmekteyiz. Modern yazılım sistemleri küçük ve birbirlerinden bağımsız çalışan modüllerden oluşmakta. Bunu sağlamak için microservice, webservice, rest ve soa gibi mimariler ve kubernetes, docker ve cloud gibi altyapı ve teknolojiler tercih edilmekte. Belli bir büyüklüğü geçmeyen ve otonom çalışan kod birimlerinin bakımı, geliştirilmesi, test edilmesi, sürümlenmesi ve işletilmesi geçmişe nazaran çok daha kolay.

Günümüzde yazılım ekiplerinin yapıları da değişmeye başladı. Örneğin Google bünyeside SRE olarak bilinen takımlar, test etmeden işletime kadar uygulamanın her yönüyle ilgileniyorlar. Birçok yeni ekip iki pizza prensibine göre oluşturuluyor. İki pizza ile doymayan bir ekip, büyüklüğü itibari ile monolite dönebilecek yapılar oluşturma eğilimi gösterebilmektedir. Küçük ekip ve tek sorumluluk prensibi kolay değiştirilebilir ve geliştirilebilir yazılım birimleri için sihirli bir formül haline geldi.

Bunun yanı sıra yazılımcılar eskiye nazaran tasarım prenbipleri, tasarım şablonları ve yazılım mimarileri konularında daha donanımlı hale geldiler. Clean code, software craftşman ve devops akımları, yazılımcıların teknik olarak daha da iyi olmaları için gerekli fikir ve pratikleri ihtiva ediyorlar. Ayrıca günümüzde eskiye kıyasla yazılımda teknik sürdürülebilirliği destekleyici, sonar, jenkins, git gibi birçok açık kaynaklı ürün bulmak mümkün.

Müşteri cephesinde de bazı değişiklilerin meydana geldiğini görmekteyiz. Müşteri eskisi gibi artık yıllar sonra kullanmaya başlayacağı bir yazılım ürünü siparişi vermek istemiyor. Müşteri bugün siparişini verdiği yazılım ürününün ilk sürümünü birkaç hafta sonra kullanmaya başlamak isteyebiliyor. Buna sadece çevik süreç ve iterasyon bazlı çalışma ile cevap vermek mümkün. Ayrıca müşteri için bir yazılım ürününün kullanılabilirlik seviyesi de değişmiş durumda. Piyasa rekabetinden doğan yeni gereksinimlerinden dolayı müşteri yıllarca beklemek yerine, sürekli geliştirilen, gereksinimler doğrultusunda adapte edilen ve her daim kullanılabliir yazılım ürünlerine yönelebiliyor.

Yirmi sene öncesi çevik süreçler ve tdd, bdd, pair programming, ci, refaçtoring, solid gibi çevik metotlar uygulanmaya başlandığında devir monolitlerin hakim olduğu mimarı devirdi . Çevik süreç ile bir monolit geliştirmek sadece iyi bir niyetten öteye gidemedi ve bu yüzden çevik süreçlerin bir işe yaramadığı düşünüldü. Oysaki container ve microservice dünyası için çevik süreç biçilmiş bir kaftan. Yıldızı söndüğü zannedilen çevik süreçler bulut bilişim ile ne olduklarını ispatlayacaklar.


Not: Eğer extreme programming gibi safkan bir çevik sürecin nasıl işlediğini merak ediyorsanız, size pratik agile isimli ücresiz kitabımı tavsiye etmek isterim. Çevik süreçler hakkındaki yazılarıma buradan, buradan ve buradan ulaşabilirsiniz.


EOF (End Of Fun)
Özcan Acar