---
title: "Ruby'nin Tasarım Felsefesi"
source: 'https://academia.sh/tr/kurslar/ruby-temelleri/rubynin-tasarim-felsefesi'
course: 'Ruby Temelleri'
language: tr
updated: '2026-10-21T05:03:43+00:00'
license: 'CC BY-SA 4.0'
objectives:
    - 'İşleçlerin ve okunur yöntem adlarının aynı düzenekle, bir iletiyle çalıştığını koşumla gösterir'
    - 'Bir iletinin sınıf, modül, blok ya da sözdizimi tarafından yanıtlandığını kurala göre sınıflandırır'
    - 'Bir modülün yeteneği alıcının sınıfındaki bir yönteme dayandırdığını sahip ölçümüyle ayırt eder'
---

# Ruby'nin Tasarım Felsefesi

Ruby'de 5 + 3, x = 5, bir dizinin map'i ve 5.between?(1, 10) aynı biçimde yazılır; sonucu üreten kod ise dört ayrı yerde durur. Ders bu dört yanıtlayanı on iki gözlemle ölçer ve okunabilirliği önceleyen tasarımın işleçleri bile yönteme çevirdiğini gösterir.

M12 PHP ile kapandı. Orada bir sorunun hangi kanaldan duyulduğu, bir değişikliğin nereye ulaştığı ve bir parçanın bir istekte koşup koşmadığı ölçüldü. Ruby müfredatı başka bir sorudan başlar. `5 + 3`, `x = 5`, `[1, 2, 3].map { ... }` ve `5.between?(1, 10)` ekranda aynı biçimde yazılır: bir değer, bir nokta ya da işleç, bir ad. Ama bu dört ifadenin sonucunu üreten kod dört ayrı yerde durur. Bu kurs her düzeneği tek bir soruyla ölçer: bu iletiyi kim yanıtlıyor?

İleti (message), bir nesneye gönderilen ad ve argümanlardır; iletiyi alan nesneye alıcı (receiver), iletiye karşılık çalışan koda yöntem (method) denir. Programlama Temelleri kursunda (M01/K02) değişken, tip ve fonksiyon kavramları kurulmuştu; burada yeni olan, bu kavramların Ruby'de hangi düzenekle verildiğidir. Bu ders düzeneğin dilini ve ölçünün çekirdeğini kurar, sonraki beş ders aynı çekirdekten birer kesit alır.

## Dört Yanıtlayan

Bir iletiyi karşılayan kodun bulunabileceği dört yer vardır. Kurs boyunca bu dört ad değişmez; kategorinin üst adı **yanıtlayan**dır. "Sınıf" sözcüğü Ruby'nin `Class`'ıyla çakıştığı için ölçü kategorisi yazılırken "yanıtlayan sınıf" ya da "sınıf yanıtlayanı" denir; çıplak "sınıf" yalnız Ruby sınıfıdır.

| Yanıtlayan | Tanım |
|---|---|
| sınıf | İletiyi karşılayan yöntem, alıcının ait olduğu bir sınıfta tanımlıdır |
| modül | Yöntem bir modülde (module) tanımlıdır ve sınıfa karıştırılmıştır |
| blok | Yöntem çağıranın verdiği bloğa dayanır; aynı ileti başka blokla başka sonuç verir |
| sözdizimi | Ortada ileti yoktur; ifadeyi dilin kendisi işler |

Bu ayrım önceki müfredatlardaki bir soruya benzer görünür ama aynı değildir. M08/K03'te bir davranışın kimin sözü olduğu soruldu: dil mi, kitaplık mı, programcı mı vaat ediyor. Burada söz aranmaz, kod aranır; ölçülen, davranışı vaat eden taraf değil, iletiyi o anda karşılayan tanımdır.

**DT1.** Bu derste "yanıtlayan", iletiyi karşılayan yöntemin tanımının bulunduğu yerdir. Yöntemin hangi sırayla aranıp bulunduğu bu kursta ölçülmez; yalnız sonuç, yani sahip ölçülür. Arama sırası müfredatın bir sonraki kursunun konusudur.

## Okunabilirlik Önceliği

Ruby'nin tasarım tercihi, kodun bir cümle gibi okunmasını işleç ekonomisinin önüne koymaktır. Bu tercih en açık biçimde adlandırılmış yöntemlerde görülür: `5.between?(1, 10)` ifadesi okunduğu gibi bir sorudur. İkinci sonuç daha az görünürdür: işleçler de yöntemdir. Aşağıdaki dosya aynı toplamı üç yazımla verir.

```ruby
# isleclar.rb — isleclerin de yontem oldugunu gosterir
puts 1 + 2
puts 1.+(2)
puts 5.send(:+, 3)
puts 5.between?(1, 10)
puts 5.clamp(1, 3)
```

```
3
3
8
true
3
```

`1 + 2` ile `1.+(2)` aynı sonucu verir, çünkü ilki ikincinin kısa yazımıdır: alıcı `1`, ileti `+`, argüman `2`. `send` iletinin adını sembol olarak alır ve `5.send(:+, 3)` aynı iletiyi gönderir. Böylece `5 + 3`, `x.upcase` ve `5.between?(1, 10)` arasında yazım farkı kalsa da düzenek farkı kalmaz: üçü de bir alıcıya gönderilen birer iletidir. Bu, sonraki derslerin dayandığı sezgidir; her işlemin bir ileti olduğu bir dilde "kim yanıtlıyor" sorusu anlamlı olur.

**DT2.** Ölçümler Ruby 4.0.7'de koşturuldu. Bir yöntemin hangi sınıfta ya da modülde tanımlı olduğu sürümden sürüme taşınabilir; derste yazılan sahip adları bu sürümün sonucudur, dilin sözü değildir.

## Aynı İşin İki Yazımı

Okunabilirlik tercihi yalnız yöntem adlarında değil, aynı işin birden çok yazıma sahip olmasında da görünür. Ruby'de bir işi görmenin tek yolu yoktur ve yazarın seçtiği yazım, okuyana işin amacını ne kadar açık söylediğini belirler. Aşağıdaki iki dosya bu tercihin ölçülebilir kısmını sorar: aynı işin iki yazımı yalnız görünüşte mi ayrılır, yoksa farklı bir yöntemi mi çağırır? Ölçü ekseni yanıtlayandır; her yazımın iletisini kimin karşıladığı, mümkün olan yerde, çıktının yanında basılır.

```ruby
# iki_yazim.rb — ayni isin iki yazimi ve yanitlayanlari
dizi = [4, 5, 6]
sayac = 0
dizi.each { |n| sayac += n }
puts sayac
puts dizi.sum
puts dizi.method(:each).owner
puts dizi.method(:sum).owner
x = 7
puts "kucuk" unless x > 10
puts "kucuk" if !(x > 10)
```

```
15
15
Array
Array
kucuk
kucuk
```

Sayaçlı yazım ile `sum` aynı toplamı, `15`'i verdi. İkisinin yanıtlayanı da `Array` çıktı: `each` de `sum` da dizinin sınıfında tanımlıdır. Yani iki yazım arasındaki fark yanıtlayanda değil, okumadadır. Sayaçlı yazımda bir değişkenin açılması, bir bloğun yazılması ve bloğun içinde değişkenin güncellenmesi birlikte okunur; `sum` yazımında ise niyet tek adla söylenir. `unless` ile olumsuzlamalı `if` ise aynı satırı iki kez bastırdı. Burada yanıtlayan sorusu farklı bir cevap taşır: `unless` ve `if` anahtar sözcüktür, bir yöntem değildir; bu yüzden bu iki satırın yanıtlayanı olarak dilin sözdizimi sayılır. Koşulun içindeki `x > 10` ise bir iletidir; sahibi bu dosyada basılmadı. Olumsuzlamalı yazımdaki olumsuzlama işleci de ayrı bir iletidir ve `unless` yazımında bulunmaz; onun sahibi de burada ölçülmedi. Olumsuz bir koşulu tersine çevirip olumsuzlamalı `if` ile yazmak da çalışır, ancak okuyan iki ayrı işlem, önce karşılaştırmayı, sonra olumsuzlamayı zihninde birleştirmek zorunda kalır.

```ruby
# parantez.rb — parantezli ve parantezsiz cagri ayni iletidir
liste = [3, 1, 2]
a = liste.push 9
b = liste.push(9)
puts a.equal?(b)
puts liste.size
puts liste.method(:push).owner
puts liste.sort.first
puts liste.sort().first()
puts method(:puts).owner
```

```
true
5
Array
1
1
Kernel
```

Parantezsiz `liste.push 9` ile parantezli `liste.push(9)` aynı diziyi döndürdü: `equal?` `true` verdi. İki çağrı da aynı nesneyi geri verdi ve dizi iki kez büyüyerek 5 elemana ulaştı. `push` iletisinin yanıtlayanı `Array`'dir. `sort.first` ile `sort().first()` aynı `1` değerini verdi, ve `puts` çağrısının sahibi `Kernel` çıktı. İki yazım çiftinin hiçbiri ayrı bir düzenek değildir: parantez yalnız argümanların nerede bittiğini işaretler, ne alıcıyı ne de iletiyi değiştirir. Bu ölçümden çıkan kural şudur: Ruby'de okunabilirlik, yazarın elindeki bir serbestliktir ve serbestlik düzeneği değiştirmez. Aynı işi görmek için seçilen yazım, makinenin değil okuyanın işini kolaylaştırmalıdır.

**DT3.** Hangi yazımın daha çabuk okunduğu ölçülmedi. Ölçülen yalnızca, iki yazımın aynı sonucu verdiği ve yanıtlayanın değişmediğidir; okunabilirlik yargısı ekibin yazım tercihine bağlıdır ve bu kursun savı değildir.

## Okunabilirliğin Sınırı

Okunabilirlik önceliği bir serbestlik tanır, ama her serbestlik iletiyi değiştirmeden yazılamaz. Bu bölümün sorusu şudur: yazımın değiştiği yerde ileti de değişir mi? İki yazım yan yana konunca bazen ileti aynı kalır, bazen de yazım farkı ayrı bir iletiye karşılık gelir. Ölçü yanıtlayan ve sonuçtur; dosya kullanılan dört iletinin sahibini basar.

```ruby
# yazim_sinir.rb — yazim degisince ileti degisir mi
a = 2
b = 3
puts a + b * 2
toplam = (a + b) * 2
puts toplam == 10
puts a.+(b).*(2)
puts a.method(:+).owner
puts a.method(:*).owner
puts 10.fdiv(4)
puts 10 / 4
puts 10.method(:fdiv).owner
puts 10.method(:/).owner
```

```
8
true
10
Integer
Integer
2.5
2
Integer
Integer
```

`a + b * 2` ifadesi `8` verdi; çarpma toplamadan önce yapıldı. `(a + b) * 2` ise `10` verdi ve `toplam == 10` karşılaştırması `true` oldu. Üçüncü satırdaki `a.+(b).*(2)` yazımı da `10` verdi: alıcı `a`, ileti `+`, argüman `b`, ardından sonuca `*` iletisi gönderildi. Yani yazarın parantezle yaptığı öncelik seçimi, noktalı yazımda iletilerin zincirleme sırasıyla birebir aynı sonucu verir. İşleç öncelikleri bu yüzden bir yanıtlayan sorusu değildir; hangi iletinin hangi alıcıya gideceğini belirleyen bir yazım kuralıdır. Sahip satırları iki işlecin de `Integer` sınıfında tanımlı olduğunu gösterdi.

Okunabilirlik açısından ilginç olan, iki bölme yazımıdır. `10.fdiv(4)` `2.5`, `10 / 4` ise `2` verdi. İkisinin de yanıtlayanı `Integer` çıktı, ama sonuçlar farklıdır: `/` tam sayı bölmesi yapar, `fdiv` kesirli sonuç verir. Yazım farkı burada aynı işin iki biçimi değil, iki ayrı iletidir. Ruby'nin tasarımı bu ayrımı adla yapar: kesirli sonuç isteyen kişi `fdiv` yazar ve okuyan niyeti adından anlar. Bu da bölümün sonucudur: yazım serbestliği, adlandırılmış iletilerde güvenle kullanılır; işleçlerde ise sonucun aynı kalıp kalmadığı ölçülerek bilinir.

**DT4.** Tam sayı bölmesinin `Integer` için `2` verdiği bu sürümde ölçüldü. Bölme davranışının başka sayı türlerinde de aynı olduğu ölçülmedi.

## Çekirdek: Yardımcı ve On İki Gözlem

Kurs iki dosyadan oluşan bir ölçüm çekirdeği kullanır. İlki, bir iletiyi sınıflandıran yardımcıdır ve kural olarak yazılmıştır: etiket değil, soru sırası karar verir. Önce `defined?` ifadenin bir yöntem çağrısı olup olmadığını söyler; değilse yanıtlayan sözdizimidir. Sonra aynı ileti iki farklı blokla iki farklı sonuç veriyorsa yanıtlayan bloktur. Son olarak yöntemin sahibi bir `Class` örneğiyse sınıf, değilse modüldür.

```ruby
# yanit.rb — bir iletiyi kimin yanitladigini siniflandiran yardimcilar

# Siniflandirma sirayla sorar: once ifade bir ileti mi (defined?),
# sonra iki farkli blok iki farkli sonuc veriyor mu, sonra yontemin sahibi kim.
def yanitlayan(tanim, sahip: nil, sonuc: nil, bloklu: nil)
  return ["sozdizimi", "defined? #{tanim}"] unless tanim == "method"

  if bloklu
    birinci, ikinci = bloklu.call
    return ["blok", "#{birinci.inspect} / #{ikinci.inspect}"] unless birinci == ikinci
  end

  tur = sahip.instance_of?(Class) ? "sinif" : "modul"
  [tur, "#{sahip}, sonuc #{sonuc.inspect}"]
end
```

Bu dosyanın çıktı bloğu yoktur: tek başına bir şey yazdırmaz, yalnız diğer dosyanın çekeceği bir yardımcıdır. İkinci dosya on iki gözlemi yapar. Her gözlem bir lambda içindedir; lambda çağrılınca `yanitlayan` yardımcısına iletinin `defined?` sonucunu, yöntemin sahibini ve sonucunu verir. Dosya çalışma dizinine bir `not.txt` yazar, çünkü son gözlem onu okur.

```ruby
# yanitlayan.rb — on iki gozlem: bu iletiyi kim yanitliyor
require_relative "yanit"

File.write("not.txt", "ilk satir\nikinci satir\n")
sayilar = [1, 2, 3]

gozlemler = {
  "okunur karsilastirma" => -> { yanitlayan(defined?(5.between?(1, 10)), sahip: 5.method(:between?).owner, sonuc: 5.between?(1, 10)) },
  "tam sayi toplami"     => -> { yanitlayan(defined?(5 + 3), sahip: 5.method(:+).owner, sonuc: 5 + 3) },
  "yerel atama"          => -> { yanitlayan(defined?(x = 5)) },
  "aralik eslesmesi"     => -> { yanitlayan(defined?((1..10) === 7), sahip: (1..10).method(:===).owner, sonuc: (1..10) === 7) },
  "alicisiz cagri"       => -> { yanitlayan(defined?(format("%03d", 7)), sahip: method(:format).owner, sonuc: format("%03d", 7)) },
  "sembole donusum"      => -> { yanitlayan(defined?("ad".to_sym), sahip: "ad".method(:to_sym).owner, sonuc: "ad".to_sym) },
  "varsayilan deger"     => -> { yanitlayan(defined?(Hash.new), bloklu: -> { [Hash.new { 0 }[:x], Hash.new { |_, k| k.to_s }[:x]] }) },
  "eleman donusumu"      => -> { yanitlayan(defined?(sayilar.map), bloklu: -> { [sayilar.map { |n| n * 2 }, sayilar.map { |n| n.to_s }] }) },
  "dilimleme"            => -> { yanitlayan(defined?((1..5).each_slice(2)), sahip: (1..5).method(:each_slice).owner, sonuc: (1..5).each_slice(2).to_a) },
  "lambda cagrisi"       => -> { yanitlayan(defined?(->(n) { n * 2 }.call(3)), sahip: ->(n) { n * 2 }.method(:call).owner, sonuc: ->(n) { n * 2 }.call(3)) },
  "kurtarma"             => -> { yanitlayan(defined?(begin; Integer("x"); rescue ArgumentError; 0; end)) },
  "dosya okuma"          => -> { yanitlayan(defined?(File.open("not.txt")), bloklu: -> { [File.open("not.txt") { |f| f.gets.chomp }, File.open("not.txt") { |f| f.readlines.size }] }) },
}

adet = { "sinif" => 0, "modul" => 0, "blok" => 0, "sozdizimi" => 0 }

printf("%-22s%-11s%s\n", "gozlem", "yanitlayan", "kanit")
gozlemler.each do |ad, gozlem|
  tur, kanit = gozlem.call
  adet[tur] += 1
  printf("%-22s%-11s%s\n", ad, tur, kanit)
end

puts
adet.each { |tur, n| printf("%-11s%d\n", tur, n) }
puts "toplam gozlem: #{adet.values.sum}"
```

```
gozlem                yanitlayan kanit
okunur karsilastirma  modul      Comparable, sonuc true
tam sayi toplami      sinif      Integer, sonuc 8
yerel atama           sozdizimi  defined? assignment
aralik eslesmesi      sinif      Range, sonuc true
alicisiz cagri        modul      Kernel, sonuc "007"
sembole donusum       sinif      String, sonuc :ad
varsayilan deger      blok       0 / "x"
eleman donusumu       blok       [2, 4, 6] / ["1", "2", "3"]
dilimleme             modul      Enumerable, sonuc [[1, 2], [3, 4], [5]]
lambda cagrisi        sinif      Proc, sonuc 6
kurtarma              sozdizimi  defined? expression
dosya okuma           blok       "ilk satir" / 2

sinif      4
modul      3
blok       3
sozdizimi  2
toplam gozlem: 12
```

On iki gözlemin 4'ünü bir sınıf, 3'ünü bir modül, 3'ünü bir blok yanıtladı; 2'sinde ileti yoktu, ifadeyi sözdizimi işledi. Bu sayılar kursun bütün dersleri için bağlayıcıdır: sonraki dersler bu sayıları değiştirmez, her biri tablodan kendi satırını alıp ayrıntısında ölçer.

Tablodan dört okuma çıkar. Sınıf yanıtlayanı en dolaysız olanıdır: `5 + 3`'teki `+` bir işleç gibi görünür ama `Integer` sınıfında tanımlı bir yöntemdir; `"ad".to_sym` `String`'de, lambda'nın `call`'ı `Proc`'ta tanımlıdır. Modül yanıtlayanı sınıfın kendisinde bulunmayan bir yeteneği gösterir: `between?` `Integer`'da değil `Comparable`'dadır, `each_slice` `Range`'te değil `Enumerable`'dadır, alıcısız `format` `Kernel`'dedir. Blok yanıtlayanı sonucu çağırana bırakır: `Hash.new`, `map` ve `File.open` aynı iletiyle iki sonuç verdi ve fark yalnız verilen bloktaydı. Sözdizimi yanıtlayanında alıcı da ileti de yoktur: `x = 5` için `defined?` `"assignment"`, `begin ... rescue ... end` için `"expression"` döndürdü.

Çıktıda bilerek basılmayan şeyler de vardır: `object_id`, bellek adresi taşıyan `inspect` çıktısı ve istisna ileti metni. Bu değerler her koşumda değişir ya da ortama bağlıdır; yerlerine sınıf adı, mantıksal sonuç ve sayı basılır.

## Sınırlayıcı Ölçüm

Bu dersin satırı `okunur karsilastirma`'dır ve yanıtlayanı modüldür: `5.between?(1, 10)` iletisini `Comparable` karşılar. Ancak bu cümle yarım kalırsa yanıltır. Modülün tanımladığı yöntem, karşılaştırmanın kendisini yapmaz; onu alıcıya sorar. `between?` bir değerin iki sınır arasında olup olmadığını söylemek için `<=>` iletisini alıcıya gönderir ve karşılaştırmanın nasıl yapılacağı alıcının sınıfındaki `<=>` yöntemindedir. Sahipleri yan yana basalım.

```ruby
# karsilastirma.rb — between? Comparable'da, <=> ise alicinin sinifinda
[5, "a", :a].each do |alici|
  printf("%-4s between? %-11s <=> %s\n", alici.inspect, alici.method(:between?).owner, alici.method(:<=>).owner)
end
```

```
5    between? Comparable  <=> Integer
"a"  between? Comparable  <=> String
:a   between? Comparable  <=> Symbol
```

Üç alıcıda `between?`'in sahibi aynıdır, `<=>`'in sahibi her seferinde alıcının kendi sınıfıdır. Aynı modül üç ayrı sınıfa aynı yeteneği verir, çünkü üçü de karşılaştırmayı kendisi yanıtlar. Modül bu yüzden tek başına yanıt vermez: yeteneği modülden gelir, dayanağı sınıftan.

Bu sınır, yanıtlayanı tek bir sahip adına indirgemeyi engeller. Dört yanıtlayanlı sınıflandırma iletiyi karşılayan tanımı bulur; o tanımın başka bir iletiye dayanması, yeni bir ölçüm sorusudur ve çoğu zaman cevabı bir sınıftır.

## Özet

- Ruby'de her işlem bir alıcıya gönderilen iletidir; `1 + 2` ile `1.+(2)` aynı iletidir ve `send` iletiyi adıyla gönderir.
- Ölçü sorusu "bu iletiyi kim yanıtlıyor"dur ve dört yanıtlayanı vardır: sınıf, modül, blok, sözdizimi.
- Yanıtlayanı etiket değil kural verir: önce `defined?`, sonra iki blokla karşılaştırma, sonra yöntemin sahibi.
- Çekirdeğin on iki gözleminde dağılım 4 sınıf, 3 modül, 3 blok ve 2 sözdizimidir.
- Bu dersin yanıtlayanı modüldür: `between?` `Comparable`'dadır, ama karşılaştırmanın kendisi olan `<=>` alıcının sınıfındadır.
- Aynı işin iki yazımı (`each` ile sayaç ve `sum`, parantezli ve parantezsiz çağrı) ölçülen sahipleri değiştirmedi; `unless` ile olumsuzlamalı `if` aynı sonucu verdi. Okunabilirlik yazarın seçimidir, düzeneği değiştirmez.

## Sonraki Adım

`5 + 3`'ün `+`'sının `Integer`'da tanımlı olması bir şeyi gizli varsayar: `5` bir nesnedir ve bir sınıfa aittir. İlkel değerlerin de nesne olup olmadığı ve alıcı ile yanıtlayanın birbirinden nasıl ayrıldığı sonraki dersin, Nesne Modeli Sezgisi'nin konusudur.
