Photo by Sharon Pittaway on Unsplash

JS ile Fonksiyonel Programlama

Imperative/Declarative Programlama

Imperative ile Declarative Programlama Arasında Ne Gibi Farklar Bulunur? Structural, Procedural, Nesne Tabanlı Programlama Imperative yaklaşımı kullanırken, Neden Fonksiyonel Programlama Declarative yaklaşımı kullanır? Avantaj ve dezavantajları nelerdir?

Onur Dayıbaşı
Frontend Development With JS
6 min readJan 16, 2020

--

Bu yazıyı daha önceden yazmış olduğum JS ile Fonksiyonel Programlama yazısının bir devamı olarak yazıyorum. Bir çok kavramı tek bir yazıda ele almanın yaratacağı karmaşıklıktan kaçmak için bu şekilde bir yönteme başvurdum.

Öncelikle Fonksiyonel programlamalar Declarative programlamadır. Bu yöntemin Imperative’den farkının ne olduğunu anlatarak Fonksiyonel programlamaya giriş yapmanın daha doğru olacağını düşünüyorum.

Bu blog yazımda özetle;

  • Imperative ve Declarative Kavramları Arasındaki Fark
  • Imperative ve Declarative Örnek Kullanımları
  • Imperative Programlama Yaklaşımının Tarihsel Gelişimi
  • Fonksiyonel Programlamanın Imperative Yapıları Kullanmaması

1. Imperative ve Declarative Kavramları Arasındaki Fark

Imperative Türkçede emir, buyruk, zorunluluk anlamına geliyor. Declarative ise bildiren, açıklayan anlamındadır. Yabancılar ise imperative işlemi nasıl yapacağını anlattığın, declarative ise ne yapacağını anlattığın programlama şekli olarak tanımlıyorlar.

Nasıl ile Ne bu kadar farklı programlama paradigmaları nasıl ortaya çıkarabilir diye düşünebilirsiniz. Ama işleri oldukça değiştiriyor. Örneğin bir çizim programı tasarlayalım.

Imperative Yöntem

// Diktörgen Çizme
kalemiSuPozisyonaGötür()
kalemiBastır()
kalemiSuPozisyonaSürükle()
kalemiSuPosizyondaDurdur()
kalemiSuPozisyonaSürükle()
kalemiSuPosizyondaDurdur()
kalemiSuPozisyonaSürükle()
kalemiSuPozisyonaDurdur()
kalemiSuPozisyonaSürükle()
kalemiSuPozisyonaDurdur()
kalemiKaldır()

İmperative yöntemde açıklayıcı emirlerle işlemi detaylı bir şekilde gerçekleştiririz.

Declarative Yöntem

diktorgen(ciz)

Declarative yöntemde sadece yapacağınız şeyi anlatırsınız. Tabi bu soyutlama arka planda diktörgen fonksiyonu mantığını bu fonksiyonda çiz fonksiyon mantığını buda arka planda kalemi işletilme mantığını sizden soyutlar. Ama mathematikteki f(g(x)) fonksiyonlar ile kodu geliştirmenizi sağlar.

Bu iki yöntem farklı programlama paradigmalarının oluşmasına neden olmuştur.

  • implementation/gerçekleştirim detaylarının anlaşılmasının çok zor olduğu bir DSL(Domain Spesific Language) ile gerçekleştirimi yönetme/soyutlama ihtiyacı olan programlamalarda Declarative Yaklaşımı tercih etmelisiniz.

Database Processing (SQL) sizi veritabanının bir çok gerçekleştirim detayından kurtarır. bu üst seviye Query Dili sayesinde istediğiniz gibi veritabanını kontrol edebilirsiniz. Sizin için alttaki detaylardan kurtan bir standarttır. Bu gerçekleştirimi Oracle, MySQL, MSSQL, PostgreSQL, Aurora vs.. kimin yapacağı ve nasıl yaptığı sizi ilgilendirmez.

select * from students where score>80

HTML: Web sayfası oluşturmanız için size bir markup dili verir. Bunu tarayıcıların nasıl render edeceği sizi ilgilendirmez. Bu markup dili sizin tanımlarınızdan DOM, CSS, JS birleştirerek Web sayfasını renderler ve kullanıcı etkileşimlerini handle edecek kodları ve styling kodlarını yükler. Bunun için alttaki detaylar ile uğraşmanız gerekmez. Üst seviye declarative tanımları bilmeniz yeterli

<html>
<head></head>
<body>
<h1>Declarative Programlama</h1>
<p>Lorem ....</p>
<body>
</html>

Regex: Str içerisinde bir takım pattern/örüntüler ile arama yapacaksınız. Bunu kod ile yapmaya çalışsanız bir çok fonksiyon yazmanız lazım ve çok performanslı gerçekleştiremeyebilirsiniz. Regex declarative dili sayesinde bu işi çok basit bir şekilde yapabilirsiniz ama ne yapacağını söylersiniz arka planı regex motoru halleder.

function escapeRegExp(str) {
var regex = /\$!(.*?)!\$/g;
return str.replace(regex, “”);
}

Aynı örnekleri React JSX yapısı, Fonksiyonel Programlama içinde söyleyebiliriz. Hepsinde de kompleks altyapı gerçekleştirimi sizden saklayan daha üst bir Domain Dili ve bunun altında bu dilin belirttiklerini çalıştıran bir Engine/Motor vb.. olduğunu görürsünüz. Bu dilleri öğrenmesi zordur ama öğrendikten sonra daha az hataya sebep olurlar çünkü kullanıcıyı olabildiğince belli bir küme içerisinde kısıtlarlar.

  • Business application veya karmaşık iş akışlı uygulamalar geliştiriyorsanız, bunu da Imperative Yaklaşımla geliştirmeniz daha mantıklı olacaktır. Çünkü bu tip iş kurgularını belli matematiksel fonksiyonlarda toplamanız pek mümkün olmaz.

Basic, Pascal, Delphi, C, C++, Java, C# gibi diller ile bu tip çok karmaşık yapılı akışlı uygulamalar çok daha basit şekilde geliştirilebilir ve daha sonradan daha iyi bakım yapılabilir ve daha okunabilir olurlar.

Not: Bence bir benzerlikte İstatiksel Modellemelerdeki(Makine Öğrenmesinden) vermek istiyorum. Fonksiyonel programlama daha matematiksel programlama , bazen veriniz öyle bir şekildedir ki arka plandaki istatiksel modeliniz bir formül çıkarır. Logistic Regresyon , Linear Regresyon vb.. bunlar bana Fonksiyonel yaklaşımı, bazen de öyle bir veri yapınız olur ki buda ancak Decision Tree ile bu modeli tanımlayabilirsiniz bu da bana Imperative Programlamayı anımsatıyor. Modelin beyninde tutulan modellerin de Fonksiyonel/Procedural olanları var bence :)

2. Imperative ve Declarative Örnek Kullanımları

Programlama Paradigmaları
  • Imperative: Procedural Programlama Dilleri (Basic, Pascal, C, C++, Java)
  • Declarative: Fonksiyonel Programlama Dilleri ve Markup, DSL diller (SQL, Regular Expression, HTML)
  • Hybrid : Javascript, Python

3. Imperative Programlama Yaklaşımının Tarihsel Gelişimi

Imprerative Programlama Paradigma Kümesi

Öncelikle Imperative dillere bir bakalım. Imperative Programlama yaklaşımı zaman içerisinde Programlama dillerinin gelişimi ile birlikte GoTo ile Programlama→ Structured Programlama → Procedural Programlama → Object Oriented Programlama içerisinde yer almıştır ama farklı şekillerde aşağıda bunlardan bahsetmek istiyorum.

GOTO

İlk Assembly yani makine dilinde Register(yazmaç) veriyi taşı, toplama işlemi yap sonra bunu diske yaz emirlerinin olduğu kod blokları arka arka yazıldığını görebilirsiniz.

Assembly Code

Zaman içerisinde High Level Language (Yüksek seviyeli diller ile birlikte) makine dilinden uzaklaştıkça GOTO kullanımının yazılım geliştirmeye zarar verdiği ve kodun spagetti gibi karıştırdığını belirtmişlerdir. Go to Statement Considered Harmfull . ( Dijkstra 1968)

Structured Programlama

Daha sonrasında dillerin gelişimi ile birlikte yazılımı yönetme olayı için (structured) yapılsal programlama yöntemi geliştirilmiştir. Bu yöntemde GOTO metodu yerine

  • Sequences: Ardı ardına işletilen kod blokları ve subroutine (subroutine — statement, method, procedure, function)
  • Selections: Belli koşullarda (sistemin o anki state) göre subroutine çalıştırılması (Condition — if, switch)
  • Iterations: Bir döngü ile sistemin ilgili state gelinceye kadar subroutine çalıştırılması (Loops — for, while)

Peki işlem sırasında acil çıkışlar yapabilmek veya kodun sequence kodunu 1 atlayak çalıştırması için bazı özel anahtar sözcükler mevcuttur. return, break, continue, exit

Subroutine incelediğimizde statement kodun en ufak işletildiği satır, procedure basic gibi dillerde tekrar şeklinde çalıştırılan statement gruplandığı işletildiği grup. function ise bir grup statement işletilip geriye dönüş yapmasıdır. (pure function) ise bu işlem sırasında dışarıdan aldığı değerler dışında etkilenmez ve dışarı etkilemez. method ise sınıfa bağlı fonksiyon.

a=b+3; //statement//procedure bir deger dönmez.
procedure topla(&toplam,a,b){ &toplam=a+b}
//fonksiyon bir işlemi yapıp
//geriye bir değer döndürür.
//procedure bir deger dönmez.function topla(a,b){return a+b;} .
class calculator{
private result;
public method topla(a,b) {
this.result = a+b;
}
}

Procedural Programlama

Procedural Programlamada değişkenler , veri-yapıları ve sub rutinlerle uğraşan bir yapıda programlama geliştirilir. Prosedürler kendilerine verilen veri yapılarını işler. Sistemin genel bir state prosedürler arasında işletilir.

Object-Oriented Programlama

Objelerin tuttuğu state/attribute ve bu objelerin metodları üzerinden veriler işlenir. Objeler arasındaki iletişim için interface(arayüzler) kullanılır. Bu sayede objelerin birbirleri iletişimde olduğu bir yapı ortaya çıkar.

Aslında Procedural Programlamadan → Object-Oriented programlamaya geçiş sırasında (abstraction ve cohesion) genel uygulama kapsamından nasıl objeler içerisinde taşındığını ve artık daha kontrollü bir şekilde nasıl objeler ile kontrol edildiğini görebilirsiniz.

Bu geçişler, yeni programala yöntemlerinin çıkması, önceden işletim sistemi, driver yazılımı vb uygulama geliştirmeden yavaş yavaş daha enterprise(kurumsal) yazılımlara daha büyük uygulama geliştirme ihtiyaçlarının ve aynı projelerde daha fazla kişinin çalışması gerektiği için ortaya çıkmıştır.

3. Fonksiyonel Programlamanın Imperative Yapıları Kullanmaması

Kısaca Fonksiyonel programlada procedural programlama gibi aynı structured programlama yapısındaki işlemleri yapmaya çalışmaktadır. Fakat fonksiyonel programlamada imperative elemanlar ile gerçekleştirilen condition, loop kavramlarının fonksiyonel programlada kaldırılıp sistem state kullanmadan pure function ve bunun girdileri ile bu akış gerçekleştirmeye çalışılır.

Bu yapıları nasıl atabileceğimizi biraz kod ile anlatacağım. Aşağıdaki kodda ben her bir elemanı tek tek döner iken

for(let i=0;i<arr.lenght;i++) {
const element=arr[i];
console.log(element);
}

fonksiyonel programlamada sizi bir loop döngüsü yapmaktan kurtarır. kontrollü bir forEach içerisinde işleminizi yaparsınız.

arr.forEach(el=>console.log(el));

Peki bir durum oldu ve bu durumda for çıkmak istediniz. Procedural bir dilde bunu break, continue vb.. yapabilirsiniz ama fonksiyonel dil buna izin vermez o forEach bütün elemanları bitirinceye kadar dönecektir. Bunun için öncelikle arr.filter ile döngüde istemediğiniz elemanları eleyebilirsiniz.

Referanslar

Okumaya Devam Et 😃

Bu yazının devamı veya yazı grubundaki diğer yazılara erişmek için bu linke tıklayabilirsiniz.

--

--