Posted on :: Tags:

Yazılım Projeleri: Kapsamlı Rehber

Yazıya başlamadan önce, bu yazının kimlere yönelik olduğunu belirteyim.

1- Yazılımda görece yeniysen, kendini halk arasında “junior” olarak tabir edilen grupta görüyorsan,

2- Kendini geliştirmek için proje yapmak istiyor, ancak ne yapacağını bilemiyorsan,

3- Hackernews klonu gibi projelerden ziyade kendini teknik olarak geliştirebileceğin projelerle ilgilenmek istiyorsan,

4- Yazılıma “eğer uygulamamda sağlamak istediğim bir özelliğin kütüphanesi yoksa oturur kendim yazarım” bakış açısıyla bakıyorsan,

O zaman bu yazı senin için yararlı olabilir. Yakın bir arkadaşım olan Ozan Sazak ’ın aynı konuda kendi görüşlerini yazdığı bir makaleyi de aşağıya bırakıyorum, ilgini çekiyorsa onu da okuyabilirsin.

Şimdi sizin aklınızda 2 soru var. Proje nedir, nasıl yapılır?

Bir yazılım projesi bir alışveriş listesi uygulaması yazmaktan kendi programlama dilini geliştirmeye kadar çok geniş bir yelpazede yer alabilir. Aşağıda kendim bir projeyi değerlendirirken kullandığım 2 önemli ekseni içeren küçük bir tablo çizdim. Burada Teknik Derinlik projenin daha teorik, daha tasarımsal taraftaki zorluğunu anlatırken, Teknik Genişlik ise projenin ne kadar geniş bir teknoloji yelpazesi bilmeyi gerektirdiğinden bahsediyor.

Tabii bu tablo fazlasıyla basitleştirilmiş durumda şu an(bir eksende hareket ederken diğerinde tamamen sabit kalmıyoruz aslında) ancak ana fikir, bir projenin teknik derinliği olmadan teknik genişliği olabileceği, aynı zamanda teknik genişliği olmadan teknik derinliği olabileceği. En temelde baktığınızda fullstack bir şekilde son teknolojileri kullanarak geliştirdiğiniz todo uygulamasının tüm bilgilerini tarayıcıda saklayan bir ToDo uygulamasından teknik derinlik anlamında bir farkı yok, yalnızca daha fazla farklı teknolojileri birbirine entegre etmenizi gerektiriyor. Diğer yandan neredeyse hiçbir ek teknolojiye ihtiyaç duymadan yeni bir programlama dili, terminal oyunu, veri sıkıştırma uygulaması, metinden konu analizi, resim editörü oluşturabilirsiniz.

Bu yazının kalanında neden teknik derinliği yüksek ancak teknik genişliği dar projeleri daha yararlı gördüğümden bahsedip, bu tarz projelerde nasıl adımlar atılacağını anlatıp, 2 adet proje örneği vereceğim.

Proje Seçerken Neye Dikkat Etmeliyim?

Yazılımın temelinde modelleme var. Bir uygulama yazdığınızda, o uygulamada sakladığınız verileri, o uygulamanın kullanıcı arayüzünü, kullanıcı aksiyonlarını modellemeniz gerekiyor. Bu noktada kendi modellerimizi oluştururken, genelde başkalarının oluşturduğu modellerin üstüne kurguluyoruz. Veri tabanı olan interaktif bir web sitesi tasarlıyor olalım mesela, öncelikle “client/server” modelinin üzerine kurulmuş bir veri şeması oluşturuyoruz. Hangi veri nerde/nasıl saklanıyor, client ve server arasında ne gibi veriler aktarılıyor? Sonrasında genelde kullandığımız kütüphanenin ve framework’ün bize verdiği birtakım bileşenleri kullanarak kullanıcı aksiyonlarını modelliyoruz. Kullanıcının karşısındaki ekrana metin kutuları, butonlar, yazılar koyarak kullanıcının bizim uygulamamız ile etkileşime geçmesini sağlıyoruz, etkileşimin sonucuna göre uygulamamızın durumunu güncelliyoruz.

Peki bazı uygulamaları diğerinden bizim için daha zor kılan ne? Benim buradaki ilk düşüncem, aslında her türlü uygulamanın çok zor olduğu. Biz bugün bir web sitesini modellerken alttaki network’ün modeliyle ilgilenmiyoruz, o model bizim için tarayıcı tarafından soyutlanmış. Basit bir fetch ile dünyanın herhangi bir yerinden istediğimiz veriyi çekebiliyoruz, aslında arkada ne kadar kompleks bir mekanizmanın döndüğünün hiçbir şekilde farkında olmadan.

Bu noktada bir uygulamayı zor yapan ilk etmen, o uygulama için ihtiyaç duyduğumuz bileşenlere sahip olmamak. Çoğu kişinin hiç düşünmeden kullandığı bileşenlerin kendileri çoğu zaman düşünmeyeceğimiz kadar kompleks aslında. Eğer merak ediyorsanız, bir gün <input type="text"> yazdığınızda karşınıza çıkan metin kutusunu kendi kendinize sıfırdan yazmaya çalışın. Ne kadar zor olduğunu göreceksiniz.

Neyse ki, modern teknoloji, açık kaynak, yüz binlerce şirket ve milyarlarca dolar yatırım sonrasında hayal edebileceğimiz her alanda ve konuda istemeyeceğimiz kadar hazır bileşen mevcut. Elimizin altında, yalnızca birkaç sorguyla ulaşılabilir durumda bu bileşenlerin hepsi. Hiçbir şekilde sıfırdan yeni bir bileşen oluşturmadan, yalnızca varolan bileşenleri birbiriyle doğru şekilde bağlayarak yazılım ürünleri üretmek mümkün, hatta ve hatta endüstrinin ciddi bir çoğunluğu bu şekilde ilerliyor. Dolayısıyla siz de kendi hobi projenizde aynı şekilde ihtiyaç duyduğunuz bileşenleri araştırıp bularak ilerleyebilirsiniz, çok güzel projeler de yapabilirsiniz. Bu tarz projeler benim sığ ve geniş olarak nitelendirdiğim proje kümesine giriyor. Teorik bir bilgiye, matematiğe, algoritmalara, kendi veri yapınızı tasarlamaya ihtiyaç yok, bol bol araştırma yapmaya, framework ve kütüphane kullanmayı öğrenmeye, farklı araçları doğru şekillerde birleştirmeye ihtiyaç var.

Benim şahsi gözlemim, bu tarz projeler yapmanın (1) insanın motivasyonunu kırdığı, (2) uzun vadede kişinin gelişimini yavaşlattığı, (3) yeterince eğlenceli olmadığı yönünde.

Yazının başında da bahsettiğim gibi, eğer ki kütüphanesi yoksa ben oturur yazarım diyenlerdenseniz, yazının kalanında size derin ve dar projeler tasarlamayı göstereceğim.

Öğrenmeden Öğrenmek

Bu ana kadar teknik derinliğin ne demek olduğunu bilerek biraz gizledim. Teorik bilgiden kastım ne mesela? Bir proje nasıl diğerinden teknik olarak daha derin oluyor? Gelin bir vaka çalışması üzerinden gidelim.

p5.js yüzbinlerce kullanıcısı olan bir Javascript çizim kütüphanesi.

Diyelim ki ben bugün size hadi gelin sıfırdan bir tane p5 yazalım desem, ne yapardınız?

Öncelikle, birisi size böyle bir şey sorarsa kesinlikle evet demeyin. Önce projenin github’ını bir inceleyin, yüzlerce katılımcısı olan bir projeyi sıfırdan yazmak yerine ona katkıda bulunun. Diğer yandan öğrenmek amacıyla bir p5 klonu yazmak aslında çok da zor değil.

Adım 1: Basitleştirme

Bir projeye başlamanın ilk adımı projeyi basit hale getirmek. p5.js içinde ses, video, 2d/3d grafikler, kullanıcı aksiyonları, metin desteği falan derken inanılmaz büyük bir proje. Bu projeyi basitleştirmenin yolu da bunun küçük bir alt kümesini seçmek. Gelin sadece 2d grafikleri çizebileceğiniz bir kütüphane ile başlayalım. Hatta daha da basit başlayalım, ben bir resim üzerine 2 tane kare çizdirebilir miyim?

Daha önce bu konuda hiç düşünmediyseniz biraz düşünmeye çalışın. Nedir bir resim? Nasıl çizilir? Bir dikdörtgen çizmek ne demektir?

İlk başta aklınıza gelen cevap yüksek ihtimalle bir resmin pikseller bütünü olduğu olmalı. Resim çizmek demek o piksellerin her birine bir renk atamak demek. Bir dikdörtgen ise belli bir matematiksel denkleme uyan piksellerin aynı renkte boyanması. Aşağıda da basit bir typescript tanımı var resim veri yapısı için.

type Color = { r: number, g: number, b: number };
type Point = { x: number, y: number };
type Image = {
width: number,
height: number,
pixels: Map<Point, Color>
}

Mesela benim buradaki Image tanımım seyrek(sparse) bir tanım. Bir resmi aynı zamanda yoğun(dense) olarak da tanımlayabilirdim. Farklı tanımların kolaylaştırdığı farklı operasyonlar var.

type DenseImage = {
width: number,
height: number,
pixels: Color[][]
}

E peki dikdörtgen çizmek ne demek?

const rect = (img: Image, p1: Point, p2: Point, c: Color) => {

for(let i = p1.x ; i < p2.x ; i++) {
// Üst kenar
img.pixels.set({x: i, y: p1.y}, c);
// Alt kenar
img.pixels.set({x: i, y: p2.y}, c);
}

for(let i = p1.y ; i < p2.y ; i++) {
// Sol kenar
img.pixels.set({x: p1.x, y: i}, c);
// Sağ kenar
img.pixels.set({x: p2.x, y: i}, c);
}
}

Alın size bir adet dikdörtgen çizme fonksiyonu. Tabii fonksiyonun bazı eksikleri var(p1 sol üst, p2 sağ alt nokta olmak zorunda, aynı zamanda köşelerde boş pikseller var, bir de 1 kenarlar 1 piksel sadece).

Peki bu resmi üretmek kendi başına yetiyor mu? Bir de çizmek gerekmiyor mu? Bu konuda MDN’in HTML Canvas’ı kullanmak takip edebileceğiniz basit bir rehberi var, aşağıya bırakıyorum.

Öğrenmeden öğrenmek, tam olarak az önceki süreci geçirmek demek aslında.

Fark ettiyseniz HTML Canvas haricinde hiçbir ek soyutlamaya ya da teknolojiye ihtiyaç duymadık. Resimin kendisi için kendi veri modelimizi kullandık, bu modelin üzerine kendi dikdörtgen modelimizi kurguladık. Öğrenmeden öğrenmenin temeli, yeni teknolojiler veyahut soyutlamalara sırtını dayamadan mantık ve matematik üzerine kurulu bir şekilde yazılım geliştirmekten geliyor. Mesela şu anda kenarlar 1 piksel, kenar kalınlığı oluşturmak için ne yapmamız gerekirdi? Tabii ki olay sadece basitleştirerek bitmiyor. Pikseller zaten bir ızgara şeklinde olduğu için dik çizgileri çizmek çok kolay. Peki ya üçgen çizmek istersek? O zaman yamuk bir çizgi çizmemiz gerekecek. Eğer bu yamuk çizgiyi az önce dik çizgiyi çizdiğimiz gibi çizmeye çalışırsak karşımıza bir çizgiden ziyade aşağıdaki gibi kırıklı bir çizgi gelecek.

Bu noktaya kadarki mantığı takip edersek bu tarz problemleri de kendimiz çözmemiz gerektiğini söyleyeceğimi düşünebilirsiniz, bunu söylemeyeceğim. Bu tarz problemler benim teknik derinlik adını verdiğim kategoride yer alıyor. Bu problemlerin çözümleri teorik, matematiksel çözümler.

Adım 2: İşin Tekniğini Öğrenmek

Yukarıdaki problemin çözümünü araştırdığımda kısa bir çözümle 2 tane algoritma buldum.

1- Xiaolin Wu’s line algorithm

2- Bresenham’s line algorithm

Karşılaştığımız problemlere karşı genelde 3 tip yaklaşımımız var.

1- Ben bu problemi çözen bir kütüphane bulayım.

2- Ben bu problemin nasıl çözüleceğini öğrenip kendim çözeyim.

3- Ben bu problemi çözmeyeyim, ya da daha basit/farklı bir versiyonunu çözeyim.

Adım 2 , burada problemin çözümünü öğrenip kendin çözme yolunu(2. seçenek) öneriyor.

Bu noktada bir dipnot düşmek istiyorum. Bu problemleri çözmek sizin iş hayatınızda düzenli olarak yapacağınız bir iş olmayabilir. Hatta çoğu zaman eğer bir problem zaten çözülmüşse gider kütüphanesini kullanırız, neden ben kütüphane kullanmayıp var olan kütüphaneleri tekrar yazayım diye soruyor olabilirsiniz. Haklısınız. İş hayatında zaten böyle yapmalısınız, ancak yeri geldiğinde kendi problemlerinizi de çözebiliyor olmalısınız. Kendi problemlerinizi çözemiyor olmak bir problemi çözmek için bir kütüphane olmadığında (1. seçeneği uygulayamadığınızda) problemi çözmemek, belki de daha kötü bir kullanıcı tecrübesini kabul etmek(3. seçeneği uygulamak) anlamına geliyor.

Seçenek 2'yi uygulamaya devam ettikçe işiniz kolaylaşacak. Kendi problemlerinizi çözmeye alıştığınızda karşınıza gelen diğer problemlerin çözümlerine nasıl ulaşabildiğini daha iyi öğreneceksiniz, belki de normal şartlar altında kütüphane bulamadığınız için iptal edeceğiniz bir özelliği oturup vakit harcayacak ekleyeceksiniz uygulamanıza.

İşin tekniğini öğrenmek her zaman makale okumak demek değil. Soyutlamaların altını görmeye çalışmak demek. Başkalarının veri modellerini anlamaya çalışmak demek. Bir resmin 2 tane farklı gösteriminden bahsetmiştik(Sparse ve Dense), bunlar yalnızca 2 seçenek mi elimizdeki? Hangi seçeneği kullanmak hangi durumlarda daha mantıklı? JPEG, SVG, PNG, BMP gibi farklı formatlar nasıl avantajlar sağlıyor? Resimin üzerine animasyon yaratmak istesek nasıl bir veri modeli geliştirmemiz gerekir?

Soyutlamaların arkasındaki mekanikleri anladıkça, bilgisayarlar sizi daha az şaşırtmaya başlayacak. Mesela ben şu sıralar bir dosya editörü geliştiriyorum, onun yüzünden dosya editörlerinin veri modellerini anlamayı kafaya taktım biraz. Kullandığım editörlerin neyi nasıl yaptığına dikkat ederek arkadaki modeli tahmin edebiliyorum. Metnin pozisyonunu hesaplarken nasıl hesaplıyorlar, Microsoft Word’de sinir olduğum özelliklerin sebebi ne onları görebiliyorum. Yine benzer bir şekilde Whatsapp’ta bir metni aramaya çalışırken arkadaki veri yapısını hangi aramaları kolaylaştırdığı, hangi aramaları zorlaştırdığı üzerinden hayal edebiliyorum. Ne işe yarıyor bunlar derseniz, kendi kendime gülüp geçmem haricinde çok bir işime yaramıyor. Ancak bana öyle geliyor ki beni günlük hayatımda daha iyi bir mühendis ve araştırmacı haline getiriyor.

Adım 3: Yeri Geldiğinde Genişlemek

Tabii ki her maksimalist argüman gibi, öğrenmeden öğrenmenin de uç noktası pratik değil. Hiçbir teknoloji kullanmadan tüm bir uygulamayı tek başınıza yazamazsınız. Mümkün değil. Dolayısıyla neyi öğrenmek istediğinize, hangi konseptlerin ilginizi çektiğine, uygulamanızın hangi kısımlarının sizin için daha temel olduğuna göre bir öncelik geliştirip, kalan kısımda tabii ki var olan ekosisteme sırtınızı dayayabilmelisiniz. Ancak projenin temeli, sizin kendinizi geliştirmek istediğiniz domain olmalı.

Nası Projeler Seçmeliyim?

E peki nasıl bulabilirim bu tarz projeler diye düşünüyorsanız, aslında günlük hayatta kullandığınız servislerin çoğunun basit bir versiyonunu yazmayı deneyebilirsiniz.

  • Toy Version Control System: Kendi git’inizi yazmak istemez miydiniz? İstediğiniz tüm özellikleri koyma şansınız var hem de.
  • Custom Textbox: Hepimizin her gün kullandığı html textbox aslında altında çok eğlenceli mekanikler içeriyor. Yazdığınız metnin piksellerini hesaplayıp ona göre alt satıra inmeli misiniz, kullanıcı ok tuşlarına bastığında işaretçiyi nereye götürmelisiniz?
  • Toy Image Editor: Bu yazıda başladığımız sistemi bir adım öteye götürüp kendi resim editörünüzü yazmak istemez misiniz?
  • Toy Grammarly: Eğer dil bilgisi veya kuralları ilginizi çekiyorsa, yazdığınız metni kendi gramer motorunuz ile kontrol etmeye çalışmak ister misiniz?

Bu projelerden bahsetmemin sebebi, daha önce üzerine düşündüğüm, ya buna uğraşsam ne eğlenirim dediğim projeler olması. Uç seviyede bir uygulama yazmanıza gerek yok son kullanıcıyı düşünen, ancak günlük hayatta nasıl işlediğini hiç düşünmeye ihtiyaç duymadan kullandığınız uygulamaları yazmaya çalıştığınızda o uygulamalara dair olan bakış açınız da değişecek bence. Eğer ki sizin aklınıza gelen uygulamalar varsa onları da cevap olarak yazın, tartışalım!