Neden Programlama Bu Kadar Zor?

Üniversiteye ilk başladığım yıllarda – ki programlama ile tanışmam bu senelere denk geliyor – programlamanın kolay olduğunu düşünüyordum. Neden zor olduğunu düşünmeliydim ki? Bir insanın ürettiği makinaya input’ları gönderip, makinın bu inputları işlemesi ve insanların anlayabileceği output’lar üretmesi bana hep kolay görünüyordu.

 

 

 

 

 

 

 

 

 

Programcı’nın Wikipedia’daki tanımına bakarsak şöyle yazıyor;

A programmer, computer programmer, developer, coder, or software engineer is a person who writes computer software. The term computer programmer can refer to a specialist in one area of computer programming or to a generalist who writes code for many kinds of software.

Bu yüzden bence programlamayı zorlaştıran nedenlerin başında Software development process’in bir derya deniz olması geliyor;

  • Harika bir input iletme
  • Harika bir output oluşturma
  • Input’ların açık ve sade bir şekilde dokümantasyonu
  • Programın dokümantasyonu
  • Programın test edilmesi
  • Problemin iyi belirlenmesi
  • Problemin çözümünün iyi belirlenmesi
  • Ve dahası..

Bu maddelerin hepsi daha derinden incelendiğinde programlama’nın temelinde şunun olduğuna inanıyorum;

 

Programlama problem çözmektir!

Aslında bir program, bilgisayara bir problemi nasıl çözeceğini anlatır. Zira üzerinde yaşadığımız dünya problemlerle dolu ve bilgisayar biliminde bile çözülemeyen birçok problem var hala.

Fakat bilgisayardan büyük bir problemi çözmesini istediğinizde, genellikle ona bu problemi oluşturan birden fazla küçük problemlerin çözümünü anlatmak zorundasınız. Daha basit problemleri çözdüğünüzde, bilgisayara nasıl çalışması gerektiğini anlatan programları yazmak her zaman daha kolay olacaktır.

Bir macar matematikçi olan George Pólya, How to Solve It: A New Aspect of Mathematical Method isimli kitabında problem çözmeyi şöyle özetlemiş;

  1. Problemi anla.
    • Problemi kendi sözcüklerinizle tanımayabilir misin?
    • Problemi daha iyi anlamak için bir resim veya diagram çizebilir misin?
    • Çözümü bulmak için yeterli bilgi mevcut mu?
    • Problemin içerisindeki tüm kelimeleri anladınız mı?
    • Cevap almak için soru sormaya ihtiyacınız var mı?
  2. Bir plan yap.
    • Tahmin et.
    • Sıralı bir liste yap.
    • Olasılıkları ele.
    • Özel durumları değerlendir.
    • Denklemleri çöz.
  3. Planı uygula.
  4. Çalışmanı gözden geçir.

Peki ya bir problem için plan yapmak problemin kendisiyse? O probleme nasıl hamle yapacaksınız?

Pólya bu konuda şunu belirtmiş;

If you can’t solve a problem then there is an easier problem you can solve. Find it.

Peki bu ne işe yarar?

  • Daha basit problemlerin çözümü sizi daha zor problemlerin çözümüne teşvik edebilir.
  • Basit problemlerin çözümü özgüveni arttırmak için iyi bir pratiktir. Böylece basit problemlerin çözümünü içeren bir kod ile çalışmaya başlamanız size başarıya ulaştırmada yardımcı olacaktır.
  • Zor problemleri çözmede başarısız olsanız bile daha basit problemleri çözmek size kredi kazandırır.

Hemen bir örnek verelim. Bilgisayarda konsol üzerinden ardı ardına celsius ölçeğinde girilen 10 sıcaklığın Kelvin cinsinde karşılıklarını bulan bir program yazalım. Bu problemin çözümünde şu şekilde bir yol izleyebiliriz mesela;

  • Bilgisayarda konsol üzerinden girilen sadece bir değerin Kelvin değerindeki karşılığını bulmayı öğrenin.
  • Belki de bu çok zordur. O zaman bilgisayarda girilen değerlere matematiksel işlemleri uygulamayı öğrenin.
  • Belki de bu çok zordur. O zaman bilgisyara konsol üzerinden girilen sayısal değerin saklamnasını öğrenin.
  • Belki bu da çok zordur. O zaman bilgisayara konsol üzerinden sayısal değer girilmesini öğrenin.
  • Belki bu da çok zordur. O zaman bir konsol uygulaması oluşturmayı öğrenin.
  • Belki bu da çok zordur. O zaman kullandığınız dil ile Hello World yazmayı öğrenin.
  • Belki bu da çok zordur. O zaman kullandığınız IDE’yi açmayı öğrenin.

Kodlama problemlerinde de şu şekilde yollar vardır;

  • Eğer dikdörtgen çizmede bir sorununuz varsa, bunun yerine problemi çizgiler çizmeye indirgeyebilir misiniz? Peki ya noktalar oluşturmaya?
  • Eğer diskte bulunan bir text dosyasının içini okumada sorununuz varsa, bunun yerine problemi kendi yazdığınız string’leri okumaya indirgeyebilir misiniz?

 

Programlama için kötü koşullar

Eğer buraya kadar okuduysanız, programlamanın zorluğu hakkında bilgi sahibi olmuşsunuzdur. Neyseki, bu yüzden çalışma ortamları da programlamayı daha zor hale getirmek için tasarlanıyor. Muhtemelen birçoğumuz konsantrasyonumuzu bozacak gürültülere, konuşmalara, cep telefonu seslerine aşikar ortamlarda çalışıyoruz. Jeff Atwood – ki kendisi Stack Overflow kurucularından biridir – The Programmer’s Bill of Rights isimli yazısında bir programcıya sağlanması gereken tüm fiziksel ve çevresel gereksinimleri anlatıyor;

It’s unbelievable to me that a company would pay a developer $60-$100k in salary, yet cripple him or her with terrible working conditions and crusty hand-me-down hardware. This makes no business sense whatsoever. And yet I see it all the time. It’s shocking how many companies still don’t provide software developers with the essential things they need to succeed.

 

Programlama zor değil, sadece zaman alır

Hayatımda okuduğum en iyi yazılardan biri kesinlikle Peter Norvig’in yazdığı Teach Yourself Programming in Ten Years isimli makalesi.

Herhangi bir kitapçıya gittiğinizde Teach Yourself Java in 7 Days (7 Günde Java Öğrenin) benzeri, size birkaç günde veya birkaç saatte Visual Basic, Windows, Internet (vs.) öğretmeyi vadeden kitaplarla karşılaşırsınız.

Birkaç günde, Beethoven, Kuantum Fiziği ya da köpek eğitimi öğreten kitaplar yok. Bu sonuçlara bakılırsa, ya insanlar bilgisayar hakkında yeni şeyler öğrenmek için çok hevesli ve aceleci ya da bu iş bir şekilde inanılmaz derecede kolay.

İlk olarak 7 gün kayda değer programlar yazarak, yazdığınız programlardaki başarı ve başarısızlıklarınızdan ders almanıza yetecek bir süre değildir. Ne tecrübeli bir programcıyla çalışmaya, ne de o ortamın içinde yaşamanın nasıl bir şey olduğunu anlamaya zamanınız olmayacaktır. Bu durumda sadece yüzeysel bir aşinalıktan bahsedilebilir, derinlemesine bir kavramadan değil. Kısacası dili iyi öğrenmeye fırsatınız olmayacaktır. Alexander Pope’nin de söylediği gibi bir “yarı bilgili olmak çok tehlikelidir”.

Bu yazıyı ne zaman okusam, hemen aklına üniversiteden mezun olup 2-3 yıl bir şirkette tecrübe edindikten sonra “Senior Developer” olan arkadaşlarım gelir. Biraz üzücü buluyorum bu durumu doğruyu söylemek gerekirse zira onlar muhtemelen “yarı bilgili” konumundalar. Bir kısmının artık işyerinde verilen işleri yerine getirmekten başka uğraşı yoktur. Kitap okumazlar, blog yazmazlar, blog okumazlar, kod okumazlar, open source projelere katkıda bulunmazlar, başka programcılarla iletişim kurmazlar, programlama konusunda insanlara yardımcı olmazlar vs vs..

Fakat bu bir yarış değil. Kendinizi başka programcılarla karşılaştırmayın. Jeff Atwood Why I’m The Best Programmer In The World isimli yazısında şöyle diyor;

But it’s not our job to be better than anyone else; we just need to be better than we were a year ago.

F# ile Fonksiyonel Programlama

fsharpF# öğrenmeye karar verdim.

Neden mi? Aslında bunun temel olarak 3 nedeni var;

  • Hayatımda hiçbir zaman fonksiyonel programlama temelinde bir dil öğrenmedim. Bunun nedeni de galiba OOP’nin günümüzde en popüler progrmalama paradigması olmasını gösterebilirim. Üniversite hayatım boyunca ve kısa süreli çalışma hayatım boyunca fonksiyonel programlamaya hiç ihtiyaç duymamam da buna neden oldu diyebilirim.
  • “Guru” olarak adlandırabileceğim birçok kişiden bu dili öğrenmenin ne kadar eğlenceli olduğunu, uygularken de bulmaca çözmek gibi bir his verdiğini duyunca açıkçası daha fazla dayanamadım. Adeta bir lezzetli çipetpet havası var F#’ta.
  • Yeni bir programlama dili öğrenmek ne zaman eğlenceli olmadı ki?

 

Kısaca Fonksiyonel Programlama

Fonksiyonel programlama, programları, argümanları ve dönüş değeri (return value) olan fonksiyonlar toplamı olarak görür. Nesneye yönelik programlamanın aksine, iteration işlemi için loop’lar kullanmak yerine çoğunlukla recursion kullanır. Program içerisindeki fonksiyonlar daha çok matematiksel fonksiyonlara benzerler zira programın durumunu değiştirmezler. Kısaca, bir değer bir identifier’a atandığında, asla değişmez. Fonksiyonlar parametre değerlerini değiştirmezler ve bu fonksiyonların sonuçları tamamen yeni bir değer döndürürler. Daha da kısaca, bir değer bir bellek bölgesine atandığında, asla değişmez. Fonksiyon sonuçları oluşturmak ise, önce fonksiyonlar değerleri kopyalar, bu kopyalanan değerleri değiştirerek işlem yaparlar. Orijinal değerleri başka fonksiyonlar kullanabilsin diye serbest bırakırlar ve artık onlara ihtiyaçları kalmadığında boşa çıkartırlar. Garbage Collection kavramının temelini oluşturur bu.

Bu sayede Fonksiyonel programlamanın birçok karmaşık hesaplama problemlerine çözümler sunduğu söylenir.

Fonksiyonel programlama ile ilgili birkaç kavramı da bilmek gerekiyor;

  • Higher order functions: Matematik ve genel bilgisayar bilim’inde bu fonksiyonlar en azından şu iki işlevden birini yapar;
    • Bir veya birden fazla fonksiyonu input alma veya
    • Output olarak bir fonksiyon verme. Diğer tüm fonksiyonlar first-order functions olarak isimlendirilir. Bu fonksiyonlara örnek olarak türev ve integral gösterilebilir. Zira ikisi de input olarak bir fonksiyon alıp geriye bir fonksiyon döndürürler. F# içerisinde bulunan List.map buna örnek olarak gösterilebilir.
  • First class functions: Bir elementin first class function olabilmesi için şunlardan biri olması gerekir;
    • Bir fonksiyona parametre olarak gönderilebilme
    • Fonksiyonlardan bir değer olarak dönebilme veya
    • Değişkenlere atanabilme. Programın herhangi bir yerinde bulunabilirler.
  • Pure functions: Bu fonksiyonlar şu iki maddeye birlikte sahiptirler;
    • Bu fonksiyonlar aynı input veya inputlarda aynı output’ları üretirler.
    • Bu fonksiyonların sonucu programda herhangi bir yan etkiye (side effect) neden olmazlar. (Mutable nesnelerin değişimi gibi veya I/O değişimi) Bu gibi fonksiyonlara örnek olarak Cos(x)  verilebilir.
  • Impure functions: Pure fonksiyonların tam tersi mantıkta çalışırlar. Örneğin;
    • Zamanı parametre alıp geriye haftanın günlerini döndüren bir fonksiyon. Zira farklı zamanlarda farklı değerler döndürebilir.
    • Random() fonksiyonu. Zira her çağırışımızda farklı bir değer döndürür. Ama Random(seed) fonksiyonu bir pure fonksiyondur. Zira bu fonksiyonu bu parametre ile her çağırışımızda aynı değer döndürür.
    • C’deki printf() fonksiyonu. Zira side effect olarak I/O’ya bir output verir.
  • Strict evaluation: Fonksiyonel programlama dilleri strict ve non-strict evaluation olarak kategorilendirilebilir. Temel konsept olarak fonksiyon argümanları nasıl işlenir ve expression’lar ne zaman hesaplanır kavramlarına dayanır bu kategorilendirme. Örneğin;
    • Strict evaluation altında
       print length([1+1, 2*2, 3/0, 4+4]) 

      kodu çalışmaz zira 3 / 0 division by zero döndürür. Fakat non-strict (lazy) evaluation altında bu geriye 4 sonucunu döndürür zira length içerisindeki expression’lar çalıştırılmaz. Sadece bunların uzunluğu bilgisi döndürülür. Strict evaluation altında bir fonksiyon çağırılmadan önce fonksiyonun tüm argümanları çalıştırılır.

Fonksiyonel programlamanın avantajlarını görmek için FP’nin yasakladıklarından çok, izin verdiği özelliklere bakılması gerektiği söylenilir. Örnek olarak fonksiyonel programlama ile fonksiyonlara bir değer gibi bakmak ve onları başka fonksiyonlara geçirmek. Bu başta pek önemli gözükmese de, etkileri olağanüstü olduğu söyleniyor. Data ve fonksiyonu birbirinden ayırmanın birçok problemin çözümüne olanak sağladığı söylenir. OOP programlamara göre FP programları daha kısa ve daha modülerdir.

Kısaca F#

F#’ın birçok sıkıntılı hesaplama problemlerini çözmek için en iyi yaklaşımlardan biri olduğu söyleniyor. F#, fonksiyonel programlama dışında imperative programming ve object-orianted yaklaşımlarına uyumluluk gösterir. Strongly typed özelliği mevcuttur, bu sayede programcıların belirsiz durumlar olmadığı sürece değişken tiplerini açıkça belirtmelerine gerek yoktur. C#’ta buna örnek olarak var keyword’ü gösterilebilir (tam karşılığı olmasa da). Bunun dışında inferred typing özelliğini de destekler.

F# bir “önce fonksiyon” (functional-first) dilidir. Buna rağmen az önce bahsettiğim gibi imperative programming ve object-orianted yaklaşımlarına da uyumluluk gösterdiğinden bu özellikler diğer Microsoft dillerine göre F#’ı daha esnek kılıyor.

F# temel olarak OCalm (object-orianted fonksiyonel programlama) dilinden modellendi. Ve .NET ile güçlendirildi. Generics kısmını hiçbir kod değiştirmeden destekler. Hatta IL (Intermediate Language) kodunu destekler. F# derleyicisi, sadece herhangi bir CLI (Common Language Infrastructure) için çalıştırılabilir dosyalar üretmez, ayrıca CLI olan her platformda çalışabilir. Bunun anlamı F# sadece Windows işletim sistemi ile sınırlı değildir. Ayrıca Linux ve Mac OS X üzerinde de çalışabilir.

Bu yazıdan yaklaşık bir ay önce OSS-approved license altında F# tamamen open source oldu. Microsoft tarafında, Visual Studio 2010, 2012 ve 2013 için tool’lar geliştiriliyor. Ayrıca F#’ın internet ortamında çok hareketli bir topluluğu mevcut. Birçok geniş ölçekli projelerde F# kullanarak katkıda bulunuyorlar. Birçok konferansta F# hakkında konuşmalar yapıyorlar. Twitter adreslerine şuradan ulaşabilirsiniz. Stack Overflow’da sorulara cevap veriyorlar. İnsanlara F# öğrenebilecekleri birçok eğitici site oluşturuyorlar.

F# Kurulumu

Yukarıda bahsettiğim gibi, F# birden fazla platformu destekler. Bu listeye buradan ulaşabilirsiniz.

Eğer windows üzerinde kullanıyorsanız, Visual Studio en iyi seçenek görünüyor. Visual Studio 2010 ve üzerinde F# default olarak kurulu olarak geliyor. Visual Studio 2008 kullanıyorsanız, MSDN üzerinden download edebilirsiniz. Eğer Vlsual Studio kullanmıyorsanız, Visual Studio Integrated Shell’i download edip, sonra F#’ı kurabilirsiniz. Temel olarak command-line compiler olan fsc.exe ve F# Interactive fsi.exe ihtiyaçlarınızı karşılayacaktır. Visual F# Resources sayfasından daha fazla bilgiye ulaşabilirsiniz.

Faydalı Linkler