Kategoriler
Teknik

Yoda Notasyonu: Nedir, Ne Değildir?

Yoda notasyonu nedir?

Yoda koşul programlama stili, daha yaygın adıyla Yoda notasyonu, mantıksal karşılaştırmalarda değişkenin ve sabitin yerini değiştirerek kullanmanızı sağlayan bir programlama tekniğidir. Genellikle koşul ifadeleri, koşullu ifadeler veya ‘if’ blokları olarak adlandırılan bu yapılar, programın belirli koşullar altında hangi eylemleri gerçekleştireceğini belirler.

"Talk is cheap, show me code" yani "Ağzı olan konuşuyor, bana koddan haber ver" ifadesini duymuşsunuzdur. İşte bu durumda, Yoda notasyonunu bir örnek üzerinden göstermek en iyisi olacak. Tipik bir koşul ifadesi şu şekilde görünebilir:

if ($değişken == null) {
    // kod
}

yerine Yoda notasyonu kullanalım:

if (null == $değişken) {
    // kod
}

Yoda notasyonunu neden kullanayım?

Bu konu hakkında bazı görüşler var. İlki mantıksal karşılaştırma yaparken bir değişken tanımlama hatasından kaçınmak. Yani iki adet eşittir işareti == koymak yerine bir adet = işareti koyduğunuzda bir değişken tanımlamış oluyorsunuz ve bu bir hataya sebebiyet veriyor. Erken dönem ve öğrenme aşamaları haricinde bu hatayı yapmış olan birileri varsa ve bunu ne sıklıkla yapıyor öğrenmek isterdim. Zira bu bana zayıf bir argüman gibi geliyor.

Yazı genelinde PHP ve JavaScript programlama dilleri üzerinden gideceğim. Ben if bloğu içerisinde bazen özellikle bir değişkene eşitlik sağlıyorum. Ama bunun hatasını hiç yapmadım. Şöyle ki:

if ($değişken = null) {
    // bu blok çok yalnız
}

Yukarıdaki kod hatalı ve değişken null değerine sahip olduğu ve null değeri de PHP’de falsy olduğu için blok içindeki kodlar çalışmayacak. Bunun yerine

if (null = $değişken) {
    // bunun yalnızlığı geçici
}

Yoda notasyonu ile bu şekilde yazmış olsaydı bir derleme hatasından dolayı yaptığımız hatanın farkına varacak ve düzeltmesini yapacaktık.

Ben bazen şu şekilde kod yazma ihtiyacı duyabiliyorum:

if ($transaction = Transaction::find(5)) {
    $transaction->notify();

    return $transaction;
}

return false;

Bazı programlama dillerinde kabul edilebilir bir durum. Ama bazı programlama dillerinde (Swift, Kotlin ve Python 3.8 sonrasında) buna izin verilmiyor. Örneğin Python’da mors operatörü := ile bu işlemi yapıyorsunuz.

Yoda Notasyonunun Artıları ve Eksileri

Yoda notasyonunun, kod okunabilirliği üzerinde pozitif ve negatif etkileri olduğunu belirtmek önemlidir. Bu notasyonun bazı artıları:

  • Yanlışlıkla atama (=) yerine karşılaştırma (==) yapma hatasını önler.
  • Hatalı kod daha hızlı fark edilir, çünkü çoğu dilde hatalı bir atama denemesi derleme hatası oluşturur.

Bazı olası eksileri:

  • Yoda notasyonu, kodun doğal dil akışına aykırıdır ve bu nedenle bazıları için daha az okunabilir olabilir. Mesela, $değişken == null ifadesi "eğer değişken null ise" olarak okunabilirken, null == $değişken ifadesi "eğer null değişken ise" olarak okunur. İkincisi, doğal dil bakış açısından biraz daha zorlayıcı olabilir.

Yoda Notasyonunun Kullanımı

Yoda notasyonu, genellikle PHP ve C dillerinde gözlemlenir. Bununla birlikte, JavaScript gibi dillerde de kullanılabilir. Bu notasyonun kullanımı genellikle kişisel veya ekip tercihlerine bağlıdır.

Örneğin, WordPress, Yoda koşullarının kullanılmasını bir kodlama standardı olarak belirlemiştir. Bununla birlikte, Symfony gibi diğer projeler bu pratiği tavsiye etmemektedir.

Yoda Notasyonu ve Okunabilirlik

Yoda notasyonunun okunabilirliği, kişinin tercihlerine bağlı olarak değişir. Bazılarına göre bu notasyon kodun anlaşılmasını zorlaştırırken, bazıları ise bu notasyonun kullanılmasının olası hataları önleyerek kodun genel kalitesini artırdığını düşünmektedir. En iyi uygulama genellikle ekibinizin ve projenizin ihtiyaçlarına ve tercihlerine bağlıdır.

Örnek:

Yoda notasyonu olmayan hali:

if (username === "Yoda") {
  console.log("May the Force be with you");
}

Yoda notasyonu olan hali:

if ("Yoda" === username) {
  console.log("May the Force be with you");
}

Sonuç olarak, Yoda notasyonu, programlama tarzı ve kodlama standartları üzerine ilginç bir konudur. Kullanımı kişisel tercihler ve belirli projelerin gerekliliklerine bağlıdır. Ancak, her iki durumda da, kodun okunabilirliği ve anlaşılabilirliği en önemli faktör olmalıdır.

Kaynakça:

Kategoriler
Teknik

MySQL’de “Truncated incorrect DOUBLE value” hatası

Her ne kadar hata içerisinde "DOUBLE value" ibaresi geçse de bu hatayı aldığınızda tablonuzda DOUBLE tipinde bir sütun mevcut olmayabilir. Bu yüzden bir kafa karışıklığı yaratabiliyor. Benim karşılaştığım, VARCHAR türünde bir sütunda INTEGER koşul sorgulama yaptığım sırada hata vermesiydi. Örnek sorguyu paylaşayım:

 update `foo_table` set `foo_type` = 'PC', `foo_table`.`updated_at` = '2022-07-23 12:32:41' where `id` >= 4843051 and `user
_id` = 8081 and `foo_id` = 12 and `foo_type` = 'CT';

Bu sorgudaki problem, foo_id sütunundaki koşulu belirtirken integer olarak koşullandırmamdan kaynaklı. Halbuki bu sütun string türünde veri de tutabilecek türde yani VARCHAR. Bu sebepten dolayı "Truncated incorrect DOUBLE value" hatası aldım. Bunu düzeltmek için foo_id koşulundaki veriyi tırnak içine aldım.

 update `foo_table` set `foo_type` = 'PC', `foo_table`.`updated_at` = '2022-07-23 12:32:41' where `id` >= 4843051 and `user
_id` = 8081 and `foo_id` = '12' and `foo_type` = 'CT';

Ve artık her şey yolunda.

Araştırdığım kadarıyla daha çok UPDATE sorgularında yaşanan bir problem ve MySQL açısından haklı bir serzeniş.

Bu hata ile karşılaşmanıza olası başka bir senaryoda şu şekildeymiş:

update students SET name='Ali' and score=9 where id=1
ERROR 1292 (22007): Truncated incorrect DOUBLE value: 'Ali'

Bu sorgudaki sıkıntı açık, UPDATE yaparken name ve score sütunlarını belirtirken AND ifadesi kullanmak. Normal şartlarda UPDATE sorgusunda güncelleme yapılacak sütunlar tanımlanırken virgül ile ayırılır. Yani:

update students SET name='Ali', score=9 where id=1

Diğer bir çözüm olarak da CAST() fonksiyonu kullanılabilir.

Ek olarak PDO veya Laravel üzerinde Eloquent ORM ile veriyi bind ederken string olarak göndermelisiniz.

Student::where('foo_id', '15')->update([...]);
Student::where('foo_id', '19RDA32')->update([...]);

PDO ile:

$statement = $pdo->prepare('update ...');
$statement->bindParam('foo_id', '15');
// veya
$statement->bindParam('foo_id', '15', \PDO::PARAM_STR);

PDO‘da, bindParam metodunda üçüncü parametre varsayılan olarak \PDO::PARAM_STR olarak tanımlıdır. Bu detayda hatanıza sebep olabilecek durumlardan birisi olabilir.

İyi çalışmalar.

Kategoriler
Teknik

PHP’de Özyinelemeli Closure Kullanımı

Bazen bir çözümü gerçekleştirmek için özyinelemeli bir fonksiyon veya metot kullanma ihtiyacımız olabiliyor. Bu ihtiyaç, benim bir kategoriye ait öğeleri ve o kategorinin alt kategorisine ait öğeleri de içine alacak şekilde Eloquent ORM’de listelemem gerektiğinde ortaya çıktı.

Bunun için, kategori modeline alt kategorilerinin ID’sini getiren bir metot ekledim. İşte bu metodun örneği:

<?php

declare(strict_types=1);

namespace App\Models;

// things...

class Category
{
    public function categories()
    {
        return $this->hasMany(Category::class);
    }

    public function getChildCategoryIDs(): array
    {
        $ids = [];

        $extract = function (Category $category, array &$ids = []) use (&$extract): void {
            $ids[] = $category->id;

            if (isset($category->categories) && is_iterable($category->categories)) {
                foreach ($category->categories as $category) {
                    $extract($category, $ids);
                }
            }
        }

        $extract($this);

        return $ids;
    }
}

Closure Kullanımı: Neden?

Bu örnekte, özyinelemeyi gerçekleştirmek için sınıf içerisinde bir metot oluşturabilirdim. Ancak bu yaklaşımın, metot sayısını artıracağı ve kodun karmaşıklığını potansiyel olarak artırabileceği göz önünde bulundurulduğunda, tüm işlemleri tek bir metot içinde gerçekleştirmeye karar verdim ve Closure’u tercih ettim.

Kategori Yapısının Sebepleri

Bu kategori yapısını, ekstra bir Laravel/PHP paketi kullanmadan ve veritabanı tablo yapısını basit tutmak amacıyla oluşturdum. Alternatif olarak, Laravel’de hiyerarşik kategori paketi olan Baum’u kullanabilirdim, ancak bu durumda ek bir bağımlılığın getireceği potansiyel karmaşıklığı tercih etmedim.

Bu yaklaşımın kısa vadede hızlı ve basit bir çözüm sağladığını, ancak uzun vadede ve artan web trafiğiyle birlikte sorgu optimizasyonu ihtiyacını doğurabileceğini unutmamak önemli. Ancak, bu potansiyel sorun, önbellek kullanımıyla çözülebilir.

Çalışma Şekli:

<?php

public function show(Category $category)
{
    $category->load('categories.categories.categories');
    $ids = $category->getChildCategoryIDs();
    $products = Product::whereIn('category_id', $ids)->get();

    return view('products.index', compact('category', 'products'));
}

CategoryController içerisindeki show metodu, belirli bir kategoriyi ve o kategorinin ürünlerini listeleyen bir işlem gerçekleştirir. ‘Lazy load’ yöntemi kullanarak, hedef kategorinin alt kategorilerini (burada üç dal alıyoruz) elde ederiz ve model içinde tanımladığımız getChildCategoryIDs metodu ile bu alt kategorilerin ID’lerini alırız. Son olarak, bu ID’lere sahip tüm ürünlerin bir listesini WHERE IN sorgusu ile elde ederiz.

Kategoriler
Teknik

JavaScript’te Reaktiviteye Pratik Alternatif: Alpine.js

AlpineJS, HTML içinde kullanabilen, reaktif olarak DOM işlemleri yapabileceğiniz ufak bir framework.

Şunu sayfaya dahil edip başlayabilirsiniz:

<script src="https://cdn.jsdelivr.net/gh/alpinejs/[email protected]/dist/alpine.js" defer></script>
  1. Örnek:
<div x-data="{message: 'Hello world!'}">
  <h1 x-text="message"></h1>
  <input type="text" x-model="message">
</div>
  1. Örnek:

    <div x-data="{items: ['first', 'second']}">
    <template x-for="item in items" :key="item">
        <div>
            <span x-text="item"></span>
        </div>
    </template>
    </div>
  2. Örnek:

    <div x-data="{open: false, toggle() { this.open = !this.open }}">
    <button @click="toggle()">
        <span x-text="open ? 'Kapat' : 'Aç'"></span>
    </button>
    <div x-show="open">
        Görüntülenecek olan içerik
    </div>
    </div>

Daha detaylı kullanımına dökümantasyonundan göz atabilirsiniz. Bazı eksiklikleri var yeni olmasından dolayı ama bu haliyle bile birçok şeye çözüm olabiliyor.

Kategoriler
Teknik

Spatie Async Paketiyle Laravel Eloquent ORM’i Kullanmak

Bir servisten yüklü miktarda veri çekip veritabanına işlemem gerekiyordu. Veriyi Guzzle’ın havuz özelliğiyle asenkron şekilde çekip veriyi işlemek içinse Spatie Async paketi kullanmam gerekti. Şu şekilde yol aldım.

Paketi composer ile kuralım:

composer require spatie/async

Kullanımı:

use SpatieAsyncPool;

$pool = Pool::create();

foreach ($things as $thing) {
    $pool->add(function () use ($thing) {
        // Do a thing
    })->then(function ($output) {
        // Handle success
    })->catch(function (Throwable $exception) {
        // Handle exception
    });
}

$pool->wait();

Yukarıdaki örnekte varsayılan ayarlamalar kullanıldı. Aşağıdaki örnekte havuza ekleyeceğimiz öğeleri Task sınıfını kullanarak ekleyip, ayarlamaları kendimiz yapacağız.

use SpatieAsyncPool;

$pool = Pool::create()
    ->concurrency(10)
    ->autoload(__DIR__ . '/vendor/autoload.php');

$pool->add(new FooTask(1));
$pool->add(new FooTask(2));
$pool->add(new FooTask(3));

$pool->wait();

Task örneği ise şöyle olacak:

class FooTask extends SpatieAsyncTask
{
    public function configure()
    {
        $app = require __DIR__ . '/../../bootstrap/app.php';
        $app->make(IlluminateContractsConsoleKernel::class)->bootstrap();
    }

    public function run()
    {
        return AppItem::create([
            'foo' => 'bar'
        ]);
    }
}

Burada önemli olan nokta configure() metodunda gereklilikleri ihtiyaçları çağırmak.

Kolay gelsin.