Yazılımın ilk 250 günü - Part 12

13 dk okuma

111. Gün

Bugün sisteme giriş yapma ve şifremi unuttum kısımları tamamlandı. Şifresini unutan kullanıcıya, tıpkı aktivasyon kodunda olduğu gibi rastgele ve geçici bir kod oluşturularak istediği yöntem ile (email veya sms) gönderilir. Bu kodun bağlı olduğu link ile sisteme gelen kullanıcı, şifresini değiştirme işlemlerine yönlendirilir fakat henüz o aşamaya gelmedim (Kullanıcının kendi bilgileri üzerine yapabileceği işlemler kısmında burası da ele alınacak. Büyük ihtimalle gelen linkten get metodu kullanılarak ve belki regex yardımıyla varolan kod alınıp doğruluğu sorgulanıp sonrasında gerekli işlemler yapılabilir). Sadece rastgele kod oluşturma, gönderme, veritabanına kaydetme, gibi işlemler bugün şifremi unuttum kısmında tamamlandı.

Sonrasında giriş ve kayıt kısımlarının front end kısmını yapılmasına hazırlanırken, hep duyulan MVC'nin ne olduğunu tekrar merak edilip ona benzer şekilde bir sistem oluşturulabilir mi diye düşünüldü. Kopyala yapıştır olan ve mantığı henüz idrak edilmeyen kodlarla yapılabilir gibi geldi. Açıkçası denendi ama kısa süre içerisinde yapılamadı (pek de kısa değil aslında) çünkü çok parçalı bir yapısı vardı ve şu an temel sorun bu olmadığı için sonrasında vazgeçildi (Vazgeçilse de en temel bazda öğrenilen ya da akılda kodlanan kısımlar da oldu: Controller=> Get ve post metodları ile model'i ilgilendiren konulara girmek isteyen kullanıcı eylemlerini içeriyor. Model=> Veritabanı ilişkileri, sistemin ana mantığını bulunduğu kısım, aslında şu an asıl ilgilendiğimiz kısım. View=> Html ve ilgili kullanıcıya gösterilen frontend kısmını temsil eden bölüm). Temel sorun websitemizin sistemini elden geldiğince çözmek, varlıklar (software entities) arası ilişki ve bağlantıları kurmak üzerine.

Yarın veritabanı ile ilgili sınıfların düzenlemesi yapılacak. Problemli kısımlar düzeltilecek. Tamamlandıktan sonra giriş ve kayıta son verilecek (get ve post ile kullanıcıdan bilgileri alıp, session ile kullanıcı oturumunu tutup, eski bir görevde kullanılan basit bir frontend kullanılacak düzenlenerek). Yarın biter diye tahmin edilmektedir. Biterse eğer, kullanıcının kendi bilgilerini güncellemesi, görmesi gibi konuların yer aldığı sınıf diyagramının iskeleti (wireframe) çıkarılmaya başlanacaktır.

112. Gün

Bugün kodlamaya devam ederim diye düşünmüştüm. Fakat sınıfın nesne olması durumunu aklım almadı. En son izah edilen şekilde açıkçası anladığımı düşünmüştüm (o aydınlanma, beyinde kıvılcım çakma hissi olmuştu) fakat, sonrasında derinlere daldıkça işin içinden çıkamadım. "Yine de öğrendiklerimi, gördüklerimi ve notlarımı yazarsam en azından benim için de referans niteliği taşıyan bir doküman oluşur" diyerek sözü uzatmadan ana konulara gelelim: Sınıf nedir? Nesne nedir? Referans nedir?

Bir ev metaforu üzerinden gidelim:

  • Class
    Bir sinif, ev icin bir tasarımdır (blueprint). Bu tasarimi kullanarak birçok ev inşa edilebilir.
  • Object
    Insa edilen (instantiate) her ev bir nesnedir, instance olarak da bilinir.
  • Reference
    Her ev bir adrese sahiptir. Eger birisine evin nerede oldugunu soylemek istersen, üzerinde adresin yazili oldugu bir karti ona verirsin. Bu kart o nesnenin referansıdır.
  • Dereferencing
    Eger evi ziyaret etmek istersen, kartın üzerinde yazılı olan adrese bakarsin. Bu da dereferencing'tir.
Not : Bir adres, nesnenin hafızada yasadigi yerdir. Referans ise adresi işaret eden (points to this address) bir değişkendir
<?php
class EvSinifi{
    public function construct(){}
    public function doSomething(){
        echo "hi there, i'm bora :)
 <br>";
    }
}
$evim = new EvSinifi();  //1
caller($evim);  //2
$evim->doSomething();  //4
 
function caller(EvSinifi $digerEvim){
    $digerEvim = new EvSinifi(); //3
}
Bu kod parçacığında neler olduğuna satır satır bakalım:
  1. "new EvSinifi()" der ki, EvSinifi tasarımını kullanarak, evin isaret edildigi bir referans return edilir. Bu referansi $evim degiskenine kopyalayabilirsin. Bir müteahhite ev yapmasini soylersin. Yapar. Sana evin adresini söyler. Sen de onu not edersin.
  2. Bu adresi bir metoda (caller) verirsin.
  3. Burada "EvSinifi $digerEvim" referansina sahibiz. Burada pass-by-value vardir. caller'in icindeki $digerEvim, $evim referansının kopyasıdır. caller'a evin adresinin oldugu kendi kartinizi verdiniz. caller bu kart ile ne yapar? Yeni ev inşa edilmesini ister ve senin verdiğin karta yeni evin adresini yazar. Unutmamali ki, caller simdi ilk eve (1. asamada insa edilen) ulasamaz. Ama o ev, onun sahip olduğu adres kartina baska bir ev yazildi diye degismez, yok olmaz.

Özetle:

  1. Müteahhitten ev inşa edilmesini iste. Etsin. Bize adres versin. Bu adresi $evim degiskenine kaydedelim (bir karta yazalim)
  2. caller'i cagiriyoruz. Bunu yapmadan once $evim'de yazan adresi caller'a verdiğimiz yeni bir karta kopyaliyoruz. caller bu karta $digerEvim diyor.
  3. caller müteahhitten yeni bir ev ister. Insa eder, yeni evin adresini verir. caller bu adresi verdiğimiz karta kopyalar.
  4. Ilk asamaya doneriz. Orjinal, degismemis karta bakariz. Kartimizda yazan eve gideriz ve orada bir seyler yapariz.

Farkli bir bakis acisi ve farkli bir örnek:

Bir televizyon (nesne) ve uzaktan kumandayi (referans) hayal edelim. Uzaktan kumanda ile televizyona bagliyiz. Eger sesi kismak, kanal değiştirmek istersek once referansi manipüle ederiz. O da nesneyi modifiye eder. Odanin icinde dolasirken hala nesneyi kontrol edersin referansin ile. Referansi kendinle beraber laip gezersin, ama televizyonu degil. Ayrica, referans televizyonsuz da kendi basina kalabilir. Bir referansin var diye bagli oldugu bir nesne vardir anlamina gelmez.

Java'dan ornek verelim:

**String s;
Burada nesne değil sadece bir referans yaratiliyor. Eğer "s" e bu noktada bir mesaj göndermek istersen, hata alirsin cunku "s" hicbir seye bagli degildir (ortada televizyon yoktur). Daha güvenli bir pratik, bir referansi yarattığında onu her zaman başlat (initializing):
**String s = "asdf";
Ancak bu özel bir Java yontemidir. Normalde nesnelerin baslamasi icin daha genel bir tip kullanilir. Bir referans yarattiginda, yeni bir nesneyi ona bağlaman gerekir. Genelde "new" operatörü ile yapilir. Burada "bu nesnelerden yeni birini bana yap" dersin:
**String s = new String("asdf");

Yukarıdaki örnekler aslında tamamen Java dilinde nesne ve sınıf arasındaki ilişki üzerine kuruludur. Şimdi ise PHP’de durumun nasıl olduğuna bakalım: Esas kaynak olarak PHP Manual’ına bakınca da nesne ve sınıfın yine Java’ya benzer şekilde bir ayrıma sahip olduğunu görülmektedir. PHP Manual- OOP Reference


Peki bu ayrım her dilde var mı? İşte burası karışık çünkü her dil farklı bir konsepte sahip anladığım kadarı ile. Objective-C’de her sınıfın bir nesne olduğunu okudum. Her sınıf bir nesne imiş. Ama bu sınıflarda bir nesne olduğu için farklı bir class’tan türemek zorunda ve bu class’a da metaclass adı verilmiş. Bir nesnenin sıradan instance ifadesi oluşu gibi, metaclass’ta bir sınıf nesnesinin ifadesiymiş (Hiç bilmediğim, ama bilenleri referans alarak söylediğim için bol miktarda -miş’li zamana yer verdim).

Smalltalk’ta ise sınıfların, sayıların, stringlerin, hatta programın kendisi dahi nesneymiş.

Kafam biraz karıştı açıkçası ama raylar yerine oturacak diye tahmin ediyorum.

113. Gün

Pass by reference ve pass by value konusuna bir gün verildi. Konu net bir şekilde anlaşıldı. Hakkında çokça soru ve cevap bulunmasına rağmen, en net cevap en sade cevaptaymış. O cevabı derinlemesine inceleyince en sonunda karşılaşılan ise yine aynı cevapmış. “Derman arardım derdime, derdim bana derman imiş; insan-ı kâmil olmaya, lazım olan irfan imiş” der gibi oldu.
$a = $b = deger; 
burada a değişkeni b değişkenine eşit değildir. b değişkeninin bulundurduğu değeri bulundurur. Pointer konusuna bakılınca bu konu daha iyi anlaşılmaktadır. a ve b değişkenleri, farklı adreslerdedir. Aralarındaki tek bağlantı, be değişkeninin sahip olduğu değeri a değişkeni kendisine kopyalamıştır.
$a = &$b = deger;
burada ise, a ve b aynı şey olarak düşünülebilir. Bir insana Tayyip ya da Recep diye seslenmek gibidir. Aynı kişiye seslenilir. Derinlere girdikçe işler karışabiliyor hala daha ama en genel manada düşününce payy by value ve pass by reference konusu net olarak anlaşıldı.
Bugün anlaşıldığında gönüllere su serpen konu ise, nesnelerin kendisinin new ile yaratılması sonucu nesne değişkenine atanmaması, değişkene sadece nesnenin konumunu bulacak olan identifier’ın atanması durumu oldu. Karışıklığa en çok sebep olan konulardan biriydi benim için.
Bugün en çok da C++ kodlarını inceledim bu konularla ilgili (işaretçi, referans, dinamik bellek ataması).

Eklemeden edemeyeceğim: Şu site benim için günün en çok ufkumu genişleten bilgileri verdi (elbette sizin bildiğiniz konular fakat benim için böyle bir etkisi oldu). Pointer Reference


Son iki gün teoriye odaklanıldı gündemde olmasa da. Yarın tekrar gündeme geri dönülecek. Görevde kalınan yerden devam edilecek.

114. Gün

Bugün ilk iş veritabanı bağlantısı ve sorular ile ilgili sınıf düzenlemesi yapıldı. Sorgu metotları farklı bir sınıf kullanarak çağrılacak sadece. O hızlıca düzeltilebilir.

Sonrasında kayıt ve giriş için yazılan kodları front end ile birleştirildi. Giriş kısmında biraz eksikler kaldı fakat bitmek üzere.

Yarın eksikleri hızlıca tamamladıktan sonra kullanıcı bilgilerini görme ve güncelleme konularında oluşturulmuş sınıf diyagramı koda dökme kısmına geçilecek. Bugün yapılanlar dışında yapılmayan ama merak edilenler vardı:
  • Hesap aktivasyonu için gerekli kodu email ile gönderdiğimi varsayıp (ilgili fonksiyon çıktısında return olarak “gönderdiğini” belirten bir varsayım), o varsayımla işlemlere devam ediyordum. mail() fonksiyonunu denemek istedim. Denedim (gerekli php.ini ve ilgili bir dosyada gerekli konfigürasyonları sağlayarak). Fakat mail SMTP sunucu hatası ile birçok defa karşılaşıp çözüm bulamadım. Hata ise büyük ihtimalle TLS-SSL port’undan kaynaklanıyor. Fakat çözemediğim için ve aynı zamanda mail göndermek için daha modern yöntemler tercih edildiği için uğraşmayı bıraktım. Farklı bir yöntem ise denemedim.
  • Günün ikinci problem ise client ip’sini nasıl almam gerektiği ile ilgiliydi. Evet, $_SERVER['REMOTE_ADDR'] kullanarak bulabileceğimi görmüştüm. Ki sanırım en iyi yol da bu. Fakat, How to get the client ip address in php şu yorumu okuyunca bir güvenlik zafiyeti bulunuyor mu diye biraz fazla sorguladım.

115. Gün

Daha önce yaptığımız çalışmalar o konularda çok daha hızlı sonuca ulaşmamı sağlıyor. Bu da oldukça pozitif bir şey diye düşünüyorum. Şu an giriş , kayıt, veritabanı konuları tamamen bitti gibi görünüyor. Ip adresi koruması kısmını kodladım fakat yarın kullanıcı tercihleri kısmını yapacağım için oradan da etkilenecek (kullanıcı koruma istediği durumda gelecek parametreyi alıp geçici koyduğum parametre yerine koyacağım aslında) o yüzden o kısmın tamamlanması için küçük bir nüans kaldı diyebilirim.

Ne yaptığımı, ne yapmam gerektiğini bildiğimi düşünüyorum. Sınıflar arasındaki ilişkileri de bir nebze kavradığımı ve onlarla kukla sanatçısı gibi oynayabildiğimi düşünüyorum (en azından benim seviyeme göre). Tasarım desenlerinde bildiklerimi değil, ihtiyaç doğrultusunda probleme en iyi yaklaşımla çözümü getirebileni seçmem gerektiğini düşünüp kullanmaya çalışıyorum. Açım, daha iyisini yapmaya, daha temizini yazmaya, kavramları daha iyi oturtmaya, sistemi tek başıma anlayabileceğim seviyeye gelmeye. İyi ki öyle. Yol çok uzun ama seyran eylemeye devam.

116. Gün

Bugün çok kayda değer bir kod yazılmadı. Daha çok neleri nasıl yapabileceğim üzerine düşünüp kurgulamaya çalıştığım bir gün oldu. Gün sonlarına doğru verim hissetmediğim için çalışılan konuyu değiştirip algoritma kitabına son 1 saat baktım. Genel olarak sakin bir gündü. Farklı bir sınıf diyagrama baktığım için ve onun da koda dökmek için çok da doğru oluşturulmadığı fark edildiği için biraz verimsiz geçti sadece. Ama toparlayacağım.

117. Gün

Kullanıcının bilgilerini güncelleme kısmına bugün bakıldı. Biraz karıştı. Şu yüzden: user sınıfının daha daha çok yönlendireceği ve detaylı mantığı içermeyeceği düşünülmüştü. Fakat bufün _set() ve _get() magic metotları user sınıfında yapılması düşünülmeyen işlemlere girildi. O yüzden çok da karıştırmanda işin içinden nasıl çıkılabilir ve iyi bir dizayn nasıl yapılabilir bugün bu düşünüldü, oluşturulmaya çalışıldı. Kayı giriş kısmı buraya göre çok daha sistemli bi şekilde yapılmıştı. Bugün biraz çarpık kentleşmeye sebep olunacakmış gibi hissedildi. Ya gecekondular yıkılacak, ya da yapılmasına izin verilmeyecek. Yarın genel yapı daha da ortaya çıkar diye düşünülmektedir.

118. Gün

118 gün içindeki en ilginci bugündü. Öncelikle kullanıcı bilgileri güncelleme ile ilgili oluşturduğum sınıf diyagramı çok geçerli değilmiş bugün çalıştığım sırada daha çok farkına vardım. Kafamda oluşturduğum konseptin dışına çıkıyorum bu da beni zorluyor. Günün çoğunluğunda bu sorunları aşmaya çalıştım fakat çalışmamı verimsiz hissedip aynı yerde bocaladığım için ilgili konularda okumalar yaptım sonrasında biraz. Yarın dinç bir şekilde ilerlemeye çalışacağım.

Bugün neden en ilginç gündü peki? Evet profesyonel hayatta böyle şeylere takılmamam düşünmemem lazım belki ama birazcık gün sonunda takılmıştı kafam. Ben ağlayan kişiyi masum sanıyordum. Son bir saat kafam o konuya geliyordu kendimi uzaklaştırsam da. Üzülmüştüm. Oysa sonra kendisi, asıl çıkarılma sebebini söyleyince yine kendi saflığıma güldüm. Biraz da olsa akıllı sanırdım kendimi fakat “hani marjinal bizdik” vakası oluşmadı değil sonunda. Gidenler gerçekten kendileri etmişler ve bulmuşlar. Ben yine işime gücüme bakıp kendimi geliştirmek için çabalayacağım.

119. Gün

Bugün sizin yazdığınız kodu canlı olarak izlemek, kod yazımına tanık olmak, anlamak ile geçti günün çoğunluğu. Analdığımı da düşünüyorum. İş çıkışında Php’ deki strict type konusu konuşulmuştu. Benim de aklıma şuradaki yazı gelmişti o anda ama tam ifade edememiştim: Why is processing a sorted array faster than processing an unsorted array

Burada anlatmak istediğine tekrar baktım. Tren analojisi vardı cevaplarda. Bugünkü konu o yüzden çok alakası olmamakla birlikte branch prediction konusunu aklıma getirmişti. Çok bilmediğim için detaylara girmeyeceğim fakat daha sonrasında araştırıp öğreneceğim çünkü merak ettim.

Günün anlam ve önemine binaen bir Niçe sözü:

“Ne çok gülmüşümdür keskin pençeleri olmadığı için kendini iyi zanneden zayıflara.”

120. Gün

Bugün namespace kullanımı, sınıfların ayrı dosyada yazılması ve o şekilde erişilmeleri, autoloader’ın kullanımı, directory yapısının nasıl olması gerektiği, PHP’de framework yazan insanların oluşturduğu bazı standartların varlığı gibi konular gündemimdeydi.

Öncelikle namespace’in eksikliğinden kaynaklanan sorunları daha önce de defalarca yaşadığım için (aynı class isimlerinin çakışması ve programın istenmeyen sonuçlar ortaya çıkarması) kullanımına daha önce bakmıştım ve neden kullanıldığını biliyordum. O yüzden o konuda bir hiçbir sıkıntı yoktu. Bugün ilk kez karşılaştığım şey ise autoloader’ın kendisiydi. Autoloader’ın ne olduğunu, nasıl çalıştığını öğrendim. Sonrasında dosyaların dizin yapısının nasıl olması gerektiğini anlamam gerekliydi. Bu konuda tek bir doğru yoktu internette. Herkes farklı yaklaşımlarda bulunmuştu directory structure için. Tek bir formül yoktu fakat genelde tercih edilen bazı çözümler bulunmaktaydı: Bu konuda ana kaynağım bu yazıydı: On structuring php projects.


Dosyaları-sınıfları arketipine göre ayırabilirim. (davranış gibi de düşünülebilir mesela controller olarak davranan dosyalar) Ya da bu dosyaları kendi özelliğine göre (feature denilmiş, mesela product ile ilgili concrete sınıfları içeren dosyaları tek bir yerde toplamak gibi) ayırabilirdim. Yazar feature’a göre göre dizin gruplamanın faydalarından bahsetmiş bolca. Örneğin bir developer dizine baktığı zaman uygulamanın ne yaptığı hakkında kısa zamanda fikir edinebilceğini belirtmiş. Çok daha derli toplu kod oluşturma söz konusu aslında. Bizim yazdığımız (daha doğrusu sizin yazdığınız) koddaki ana detaylarında biri bu yazıda da vardı: “Genel amaçlı kodu ve domain kodunu birbirinden ayır”. Core ve class’ları ayırmamızdan bahsedilmişti. Dünyanın çekirdeğinden bize lavlar gelebilirdi. Ama biz çekirdeğe inemezdik. Güneş bizi ısıtırdı, bize can verirdi. Ama biz güneşe bir şey katmadık. Güneşin bize ihtiyacı olmadı (who knows?). Aynı şekilde core klasöründe bulunan dosyaların domain class’larının bulunduğu classes klasörüne bağımlılığı yok. Ama tam tersi bir bağımlılık söz konusu.

Günün dışında bir şeyden bahsedecek olursam, dün siteye kendi bilgisayarımdan girip bakınca birkaç problem farketmiştim, siz elbette biliyorsunuzdur fakat ben yeni gördüm: bilgisayarın ekran boyutu daha küçük olduğu için karoseldeki fotoğrafların boyutlandırmasında bir hata vardı. Hatann olduğu kısımlarda calc() ile yapılan işlem iptal edilince düzelme sağlanıyordu. Ama sadece o ekran boyutları için geçerliydi. Bugün merak edip firefox’u indirdim bilgisayarıma. Ana sayfada bu sefer farklı bir şeyle daha karşılaştım: Karoselin üzerindeki kategorilerin bulunduğu kutuların (div) boyutları farklıydı bir kısmında (flex ile ilgili fakat chrome ve firefox’ta neden bir farklılık söz konusu henüz bilmiyorum).