Skip to main content

Uluslararası Projelerde Yerelleştirme Stratejileri

Isik

Isik

Backend Team Lead @ vivoo

Uluslararası Projelerde Yerelleştirme Stratejileri#

Giriş#

Günümüzde yazılım projeleri, yerel bir pazarla sınırlı kalmaktan çıkmış ve küresel bir kitleye hitap etme gerekliliği doğmuştur. Ancak, bu küresel açılım, yazılımın farklı kültürler ve diller arasında doğru bir köprü kurmasını gerektirir. Başarılı bir yerelleştirme (localization - L10n) stratejisi olmadan, ürünün kullanıcı deneyimi ciddi şekilde olumsuz etkilenebilir. Bu yazıda, uluslararası projelerde yerelleştirme stratejilerini nasıl derinlemesine uygulayabileceğinizi ele alacağız. Burada anlatılacak stratejiler hem bir localization için bir saas destek alıyorsanız, hem de kendiniz yazıyorsanız dikkate almanız gereken genel konuları teknik örneklerle kapsayacak şekilde yazılmaya çalışılmıştır.

internalization-caption-pic

Yerelleştirme (L10n) ve Uluslararasılaştırma (Internationalization - i18n)#

Yerelleştirme, bir ürünün belirli bir yerel pazara uyarlanması sürecini ifade ederken, uluslararasılaştırma, ürünün küresel ölçekte, farklı diller ve kültürel normlara uyumlu hale getirilmesi için yapılan hazırlıkları kapsar.

  • Uluslararasılaştırma (i18n): Geliştirme sürecinde, yazılımın çeşitli dil ve kültürel gereksinimlere esnek bir şekilde uyum sağlayabilmesi için altyapı ve tasarım kararlarının alınmasını içerir. Örneğin:

    • Metin ve Kaynak Ayırımı: Kod içerisine gömülü metinler yerine, dış kaynak dosyaları (resource files) kullanılarak, dil bağımsız bir yapı oluşturulur. Bu, çeviri süreçlerini kolaylaştırır ve sürüm kontrolü sağlar.
    • UI Tasarımında Esneklik: Farklı dillerdeki metinlerin uzunluk farkları, sağdan sola yazılan diller (Right-to-Left - RTL languages) veya çok baytlı karakter setlerinin (multi-byte character sets) desteklenmesi gibi unsurlar göz önünde bulundurulmalıdır.
    • Kültürel Farklılıkların Dikkate Alınması: Tarih, saat, sayı formatları gibi kültürel farklılıklar, kodlamada parametrik olarak ele alınmalı ve gerektiğinde yerel ayarlarla (locale) uyumlu hale getirilmelidir.
  • Yerelleştirme (L10n): Yazılımın spesifik bir pazarın kültürel, dilsel ve yasal gereksinimlerine göre uyarlanması sürecidir. Bu süreç, çeviriden daha fazlasını içerir:

    • Dil Çevirileri: Tercümelerin yalnızca doğru değil, aynı zamanda bağlama uygun ve kültürel olarak hassas olması gerekir.
    • Para Birimi, Tarih ve Saat Formatları: Yerel para birimi, tarih ve saat formatı gibi detaylar, kullanıcıların günlük yaşamlarındaki alışkanlıklarına uygun hale getirilmelidir.
    • Kültürel Referanslar: Ürün içerisindeki metinler, simgeler ve görsellerin, hedef kitlede olumsuz bir etki yaratmaması için kültürel uyumları gözden geçirilmelidir.

Yerelleştirme Stratejileri#

Yerelleştirme süreci, stratejik planlama ve teknik uygulamaların yanı sıra, kültürel duyarlılık gerektirir. İşte etkili yerelleştirme stratejileri:

  • Çeviri Yönetim Sistemleri (Translation Management Systems - TMS): TMS, yazılım geliştiriciler ve çevirmenler arasındaki işbirliğini optimize eden, dil dosyalarının merkezi bir sistemde yönetilmesini ve sürüm kontrolü yapılmasını sağlayan araçlardır. İyi bir TMS, çevirilerin sürekli entegrasyon ve dağıtım (CI/CD) süreçlerine entegre edilmesine olanak tanır, bu da sürümlerin tutarlılığını ve kalite kontrolünü sağlar.

  • Kültürel Uyum: Kültürel uyum, yalnızca dil çevirisiyle sınırlı kalmaz. Farklı kültürlerin değerlerine, normlarına ve sembollerine saygı göstermek gerekir. Örneğin:

    • Renk ve Görsel Seçimi: Renklerin anlamları kültürler arasında farklılık gösterebilir. Örneğin, bazı renkler bir kültürde olumlu bir anlam taşırken, başka bir kültürde olumsuz algılanabilir.
    • Semboller ve İmgeler: Sembollerin ve imgelerin yerel kültürlerde nasıl algılandığını anlamak önemlidir. Yanlış bir sembol seçimi, kullanıcılar arasında yanlış anlaşılmalara neden olabilir.
  • Yerelleştirme Testleri ve Geri Bildirim: Yerelleştirilmiş yazılımların, hedef pazarda gerçek kullanıcılarla kapsamlı test edilmesi esastır. Bu testler, dilsel ve kültürel uyumluluk açısından hataların tespit edilmesini sağlar. Geri bildirim döngüleri, bu sürecin kritik bir parçasıdır ve sürekli iyileştirmeyi destekler.

Yerelleştirme Test Süreçleri#

Yerelleştirme test süreçleri, yazılımın farklı dil ve kültürlere uygunluğunu sağlamak için kritik bir adımdır. Bu süreçte dikkat edilmesi gereken noktalar şunlardır:

  1. Testlerin Yapılandırılması: Yerelleştirme testleri, hem fonksiyonel hem de dilsel (linguistic) testleri içermelidir. Fonksiyonel testler, yazılımın farklı dillerde doğru çalışıp çalışmadığını doğrularken, dilsel testler metinlerin doğru çevrilip çevrilmediğini ve kültürel uyumluluğunu değerlendirir.

  2. Kullanılacak Araçlar: Yerelleştirme testlerinde kullanılabilecek araçlar arasında Selenium, BrowserStack, Appium gibi otomasyon araçları ve çeviri doğrulama için lokalizasyon test araçları (örneğin, LingoHub, Crowdin) bulunmaktadır. Bu araçlar, test süreçlerini hızlandırır ve hataların tespit edilmesini kolaylaştırır.

  3. Test Metrikleri: Yerelleştirme testlerinin başarısını değerlendirmek için birkaç temel metrik kullanılır:

    • Çeviri Tutarlılığı: Farklı sayfalarda veya modüllerde kullanılan terimlerin tutarlılığı.
    • Kullanıcı Deneyimi (UX) Uygunluğu: Yerelleştirilmiş UI elementlerinin kullanıcı deneyimini olumsuz etkileyip etkilemediği.
    • Hata Oranı: Çeviriden veya UI uyumsuzluklarından kaynaklanan hata sayısı.

Derinlemesine Teknik Detaylar: Yerelleştirme Sürecinin Temel Aşamaları#

  1. Metinlerin Ayıklanması ve Çeviri: Tüm metinler koddan ayrılarak dış kaynak dosyalarına taşınır. Bu, sadece çeviri sürecini kolaylaştırmakla kalmaz, aynı zamanda metinlerin kod ile bağımsız olarak yönetilmesine olanak tanır. JSON, XML veya PO dosyaları gibi formatlar, yerelleştirme sürecinde yaygın olarak kullanılır.

  2. Çok Dilli Destek İçin API Tasarımı: Çok dilli destek sunan API'ler, içeriklerin locale tabanlı olarak döndürülmesini sağlayacak şekilde tasarlanmalıdır(aşağıda biraz daha detaylı anlatacağım.) Örneğin:

    • RESTful API: İstemciden gelen taleplerde locale bilgisi header üzerinden iletilir ve sunucu, ilgili dildeki içeriği döndürür.
    • GraphQL API: Dil seçimine dayalı olarak dinamik veri getirir. Sorgular, içeriklerin hangi dilde döndürülmesi gerektiğini belirlemek için parametrik olarak yapılandırılır.
  3. UI ve UX Optimizasyonu: UI tasarımlarının, sağdan sola yazılan diller, farklı metin uzunlukları ve yerel semboller gibi değişkenlere uyum sağlayabilmesi için esnek olması gerekir. Bu esneklik, responsive tasarım ve adaptif layout'lar (adaptive layouts) ile sağlanabilir. UX testleri ise, kullanıcıların yerelleştirilmiş versiyonlarla nasıl etkileşime geçtiğini analiz eder.

  4. Yasal ve Regülasyonel Uyumluluk: Farklı ülkelerdeki veri gizliliği yasaları (örneğin, GDPR) ve sektörel düzenlemeler göz önünde bulundurulmalıdır. Bu, veri depolama ve işleme politikalarının yerel yasalara uygun hale getirilmesini gerektirir. Özellikle sağlık, finans ve eğitim gibi sektörlerde, yerelleştirme sürecinde bu gereksinimlerin karşılanması zorunludur.

  5. Veritabanı ve Altyapı Desteği: Farklı karakter setlerini ve çok dilliliği desteklemek için, veritabanı yapılandırmalarının (örneğin, UTF-8 veya UTF-16 gibi karakter setlerinin kullanımı) uygun şekilde yapılandırılması gerekir. Ayrıca, dağıtık sistemlerde performans ve ölçeklenebilirlik göz önünde bulundurulmalıdır.

Client Tarafında Çok Dilli Destek#

  1. Dil Seçimi ve Yönetimi:

    • Kullanıcı Arayüzü (UI) Dil Ayarları: İstemci uygulaması, kullanıcıya tercih ettikleri dili seçme imkanı tanımalıdır. Bu seçim, uygulama başlatıldığında bir dil seçme ekranı (language selector) ya da kullanıcı ayarları menüsü aracılığıyla sağlanabilir. Bu dil seçimi, bir "locale" değeri olarak kaydedilir ve bu değere dayalı olarak API'ye talepler yapılır.
    • Yerel Saklama (Local Storage): Seçilen dil genellikle istemci tarafında saklanır (örneğin, browser local storage, cookies veya mobile app preferences). Bu sayede, kullanıcı uygulamaya her giriş yaptığında tercih ettiği dil otomatik olarak yüklenir.
    • Otomatik Dil Algılama: İstemci uygulaması, kullanıcının tarayıcı veya cihaz ayarlarından dil tercihlerini otomatik olarak algılayabilir. Bu, özellikle ilk kullanımda kullanıcı deneyimini iyileştirir. Örneğin, navigator.language (JavaScript) veya NSLocale.current.languageCode (Swift) gibi API’ler kullanılarak, varsayılan dil belirlenebilir.
    • en-EN, en-US, fr-FR gibi terimler "locale" (yerel ayar) olarak adlandırılır ve dilin yanı sıra, belirli bir bölge veya ülkeye özgü kültürel, tarihsel, ve dilsel farklılıkları da ifade eder. Locale, genellikle iki parçadan oluşur:
    1. Dil Kodu: Bu, dilin kendisini belirtir. Örneğin:

      • en → İngilizce (English)
      • fr → Fransızca (Français)
      • de → Almanca (Deutsch)
    2. Ülke veya Bölge Kodu: Bu, dilin hangi ülke veya bölgedeki varyasyonunu ifade ettiğini belirtir. Bu kodlar, ISO 3166-1 alpha-2 standardına göre iki harfli ülke kodlarıdır. Örneğin:

      • US → Amerika Birleşik Devletleri (United States)
      • GB → Birleşik Krallık (United Kingdom)
      • FR → Fransa (France)

      Bu nedenle, en-EN ve en-US gibi locale'lar şunları ifade eder:

    • en-EN: (Bu aslında doğru bir locale değil; doğru hali en-GB olurdu) Birleşik Krallık İngilizcesi. Bu, İngiltere'de kullanılan İngilizce diline özgü dil bilgisi, yazım ve sözdizimi kurallarını belirtir.

    • en-US: Amerikan İngilizcesi. Amerika Birleşik Devletleri'nde kullanılan İngilizce diline özgü kuralları ifade eder.

      Neden Sadece en Değil de en-US veya en-GB Kullanılıyor?

      Sadece en kullanmak dilin genel bir versiyonunu ifade ederken, en-US veya en-GB gibi spesifik locale'lar, belirli bir bölgeye özgü dil varyasyonlarını dikkate alır. Bunun önemi şuradan gelir:

    1. Yazım Farklılıkları:

      • en-GB: "Colour", "favour", "centre" gibi kelimeler kullanılır.
      • en-US: "Color", "favor", "center" gibi yazımlar tercih edilir.
    2. Tarih ve Saat Formatları:

      • en-GB: Tarih formatı genellikle dd/mm/yyyy şeklindedir.
      • en-US: Tarih formatı mm/dd/yyyy şeklinde kullanılır.
    3. Para Birimi ve Diğer Kültürel Farklılıklar:

      • en-GB: Para birimi olarak GBP (£) kullanılır.
      • en-US: Para birimi olarak USD ($) kullanılır.
  2. API Taleplerinin Yapılandırılması:

    • Locale Bilgisinin Header’da Gönderilmesi: API talepleri yapılırken, istemci uygulaması, seçilen dil bilgilerini "Accept-Language" header’ı üzerinden sunucuya iletir. Örneğin, bir HTTP talebinde:
      GET /products
      Host: api.example.com
      Accept-Language: en-US
    • Parametrik Talepler: Bazı durumlarda dil bilgisi query parametresi olarak da iletilebilir. Örneğin:
      GET /products?locale=fr-FR
    • Dil ve Yerel Ayar Yönetimi: İstemci uygulaması, dilin yanı sıra tarih, saat ve sayı formatları gibi yerel ayar bilgilerini de API taleplerine dahil edebilir. Bu bilgiler, özellikle içeriklerin yerel kullanıcılara uygun bir şekilde sunulması için önemlidir.

Server Tarafında Çok Dilli Destek#

  • Bir çok yazılım frameworkü ve kütüphane kendi ekosisteminde bu konuları ele alan ve yöneten sistemlere sahipler. Bu kütüphaneleri(i18n-js, i18next python-i18n, go18n vb.) kullanarak server tarafınızı daha kolay yönetebilirsiniz.
  1. Locale Bilgisinin İşlenmesi:

    • Header’ın Pars Edilmesi: Sunucu, istemciden gelen "Accept-Language" header'ını parse ederek, en uygun dilde yanıt üretir. Header, birden fazla dil içerebilir ve sunucu, en uygun dil eşleşmesini yapar. Örneğin, "Accept-Language: en-US, en;q=0.9, fr;q=0.8" header'ını işleyerek en uygun locale belirlenir.

      from flask import request
      def get_preferred_language():
      preferred_language = request.headers.get('Accept-Language')
      # Parse and determine the best match
      return determine_lang(preferred_language)
  2. İçeriklerin Lokalize Edilmesi:

    • Veritabanı ve Locale 1: Sunucu tarafında, dil ve yerel ayar desteği için veritabanı yapısının da buna uygun şekilde tasarlanması gerekir. Örneğin, bir ürün tablosunda ürün adları ve açıklamaları farklı dillerde saklanabilir:
      CREATE TABLE products (
      id SERIAL PRIMARY KEY,
      name_en TEXT,
      name_fr TEXT,
      description_en TEXT,
      description_fr TEXT
      );
    • Veritabanı ve Locale 2: Sunucu tarafında, örneğin bir ürünün içeriklerini farklı dillere uygun sunmak istiyorsak içeriği direkt olarak belirli dildeki payload yerine ilgili translation dosyasındaki yolu(path) i de tutulabilir. Tüm içeriklerin olduğu bir json dosyanın sistemde olduğunu düşünelim:
      • en.json:
      {
      "product": {
      "apple": {
      "content": "this is apple content",
      "name": "apple"
      }
      }
      }
      • Şimdi ise bunu veritabanında bir kayıt için kullanmak istediğimiiz varsayalım. Veritabanına ilgili json ın yalnızca indexini kaydedeceğiz. Ve her bu ürüne istek atıldıgında ilgili clientın header da gönderdiği locale'e göre ilgili en.json, es.json gibi translation filedaki karşılığını clienta göndereceğiz.
      • ürüne ait rastgele bir veritabanı kaydı
      {
      "id": "$RANDOM_ID",
      "content": "product.apple.name",
      "name": "product.apple.name"
      }
    • Dil Dinamiklerinin Yönetimi: Sunucu, içeriklerin yerel versiyonlarını döndürürken performansı optimize etmek için önbellekleme (caching) stratejilerini kullanabilir. Bu, sık kullanılan dillerin içeriklerini hızlı bir şekilde sunmayı sağlar.
  3. Fallback Mekanizması:

    • Dil Desteği Olmayan Durumlar: Sunucu, istemciden gelen taleplerde desteklenmeyen bir dil belirtildiğinde, varsayılan bir dil (default locale) belirlemelidir. Örneğin, desteklenmeyen bir dil geldiğinde İngilizce (en-US) içerik döndürülebilir.

      SUPPORTED_LANGUAGES = ['en-US', 'fr-FR']
      DEFAULT_LANGUAGE = 'en-US'
      def get_locale(requested_language):
      return requested_language if requested_language in SUPPORTED_LANGUAGES else DEFAULT_LANGUAGE
  4. Veritabanı Modelleme:

    • Çok Dilli Veri Yapıları: Çok dilli içerik yönetimi, veritabanı tasarımında da kendini gösterir. Tüm dil varyasyonları için tek bir tablo yerine, ayrı lokalizasyon tabloları kullanılabilir:
      CREATE TABLE product_translations (
      id SERIAL PRIMARY KEY,
      product_id INT REFERENCES products(id),
      locale VARCHAR(10),
      name TEXT,
      description TEXT
      );
    • Veri Getirme Stratejileri: Sunucu, veritabanından veri çekerken locale bilgisine dayalı sorgular yapar. Örneğin:
      SELECT name, description FROM product_translations WHERE product_id = 1 AND locale = 'fr-FR';

API Tasarım Prensipleri#

  1. RESTful API’de Çok Dilli Destek:

    • Dil Başlığı ve Yönlendirme: RESTful API’lerde, locale bilgisi "Accept-Language" header'ında belirtilir. Sunucu, bu bilgiyi kullanarak ilgili dilde içerik üretir ve döner. Eğer içerik mevcut değilse, Fallback dil kullanılarak içerik döndürülür.
    • Versionlama ve Dil Desteği: API’lerin çok dilli destek sunarken versiyonlama yapması da gerekebilir. Örneğin, bir API v2'de daha fazla dil desteği sunabilir ve eski versiyonlarda bu diller desteklenmeyebilir.
  2. GraphQL API’de Çok Dilli Destek:

    • Dil Seçimine Dayalı Dinamik Veri Getirme: GraphQL, istemcinin spesifik dilde içerik talep edebilmesine olanak tanır. Bu, sorgunun bir parçası olarak gönderilir:
      query getProduct($locale: String!) {
      product(id: "1") {
      name(locale: $locale)
      description(locale: $locale)
      }
      }
      • Resolver Fonksiyonları: Backend’de GraphQL resolver fonksiyonları, locale parametresine göre içerik döndürür. Bu fonksiyonlar, locale’a göre veritabanından doğru içeriği çeker:
        const resolvers = {
        Query: {
        product: (_, { id, locale }) => {
        return getProductByLocale(id, locale);
        }
        }
        };
    • Dinamik İçerik ve Fallback: GraphQL, dil desteklenmediğinde fallback mekanizması uygulayarak dinamik içerik döndürebilir. Örneğin, belirli bir locale için içerik mevcut değilse, varsayılan dilde içerik sunulabilir.
  3. API Güvenliği ve Dil Yönetimi:

    • Locale Bilgilerinin Doğrulanması: Sunucu, istemciden gelen locale bilgilerinin geçerliliğini doğrulamalıdır. Bu, istemcinin sahte veya desteklenmeyen bir dil göndermesini engeller. Yanlış bir locale gönderildiğinde, uygun bir hata mesajı döndürülmelidir.

      HTTP/1.1 400 Bad Request
      Content-Type: application/json
      {
      "error": "Unsupported locale"
      }
    • Dil Bazlı Yetkilendirme: Bazı durumlarda, belirli dillerdeki içerikler yalnızca belirli kullanıcı gruplarına sunulabilir. Bu, API’nin yetkilendirme mekanizmasıyla entegre edilmelidir.

Çok Dilli API Tasarımında Performans Optimizasyonu#

  1. Önbellekleme Stratejileri:

    • Dil ve Yerel Ayar Tabanlı Caching: Çok dilli API’lerde, aynı içeriğin farklı dillerde talep edilmesi yaygındır. Bu nedenle, dil ve locale bilgisine dayalı caching stratejileri kullanılarak yanıt süreleri iyileştirilebilir. Örneğin, Varnish veya Redis kullanarak, locale tabanlı cache mekanizmaları uygulanabilir.
  2. İçerik Dağıtım Ağı (Content Delivery Network - CDN) Entegrasyonu:

    • Dil Tabanlı CDN Dağıtımı: Küresel kullanıcılar için dil tabanlı içerik dağıtımı, CDN’ler üzerinden optimize edilebilir. Bu, kullanıcıların coğrafi konumlarına en yakın sunuculardan yerel dilde içerik almalarını sağlar.
  3. Lazy Loading (Geç Yükleme):

    • Locale Tabanlı Lazy Loading: İstemciden gelen taleplerin yoğun olduğu durumlarda, çok dilli içerikler sadece ihtiyaç duyulduğunda yüklenir. Bu, özellikle geniş içerik setlerine sahip uygulamalarda performansı artırır.

Yerelleştirme Sürecinin Yönetimi ve İletişimi#

Yerelleştirme süreci, çeşitli ekiplerin işbirliğini gerektirir. Çevirmenler, geliştiriciler, proje yönetic

ileri ve yerel pazarlama ekiplerinin, süreç boyunca etkili bir şekilde iletişim kurması önemlidir.

  • Çevik (Agile) Yönetim: Çevik yöntemler kullanarak yerelleştirme sürecinin iteratif olarak yönetilmesi, sürekli geri bildirim alınmasını ve sürecin optimize edilmesini sağlar. Scrum veya Kanban gibi çevik yönetim araçları, ekiplerin yerelleştirme süreçlerini daha esnek ve verimli bir şekilde yönetmesine olanak tanır.
  • İletişim ve Eğitim: Yerelleştirme sürecinde rol alan tüm paydaşların, süreç hakkında yeterli bilgiye sahip olması gerekir. Bu nedenle, yerelleştirme öncesinde ve sırasında eğitimler düzenlenmeli, süreç boyunca açık ve sürekli iletişim kanalları açık tutulmalıdır.

i18-l10

Monilith ve Microservice Mimarilerine Genel Bakis

Isik

Isik

Backend Team Lead @ vivoo

Modern Yazılım Mimarisi (Modern Software Architecture): Monolitik (Monolithic) ve Mikroservisler (Microservices) Arasındaki Dengeyi Kurmak (Balancing the Two)#

Giriş (Introduction)#

Yazılım mimarisi (Software architecture), projelerin uzun vadeli başarısını belirleyen kritik bir unsurdur. Doğru mimari seçimler (architectural decisions), bir yazılımın gelecekteki ölçeklenebilirliği (scalability), esnekliği (flexibility) ve sürdürülebilirliği (sustainability) üzerinde doğrudan etkiye sahiptir. Monolitik yapılardan (Monolithic structures) mikroservislere (Microservices) geçiş günümüzde yaygın bir trend haline gelse de, bu dönüşüm her zaman en iyi seçenek olmayabilir. Bu yazıda, monolitik (monolithic) ve mikroservis mimarileri (microservices architectures) arasındaki derin farkları, bu mimarilerin güçlü (strengths) ve zayıf yönlerini (weaknesses), ve bir yazılım lideri olarak bu iki yaklaşım arasındaki dengeyi nasıl kurabileceğinizi detaylı bir şekilde inceleyeceğiz.

Monolitik Mimari (Monolithic Architecture): Güçlü (Strengths) ve Zayıf Yönleri (Weaknesses)#

Monolitik mimari (Monolithic architecture), tüm uygulamanın tek bir kod tabanında (single codebase) toplandığı geleneksel bir yapı sunar. Bu yapı, geliştiricilere (developers) hızlı bir başlangıç sağlarken, projenin büyümesiyle birlikte karmaşık bir hale gelebilir.

Avantajları (Advantages):

  • Basitlik (Simplicity): Monolitik yapılar (Monolithic structures), tek bir deployable unit olarak çalıştıkları için, sistemin genel karmaşıklığı (complexity) başlangıçta düşük tutulur. Bu, küçük veya orta ölçekli projelerde (small or medium-sized projects), hızlı geliştirme (rapid development) ve dağıtım süreçlerine (deployment processes) imkan tanır.
  • Düşük Overhead: Birden fazla servis (multiple services) ve bunların iletişim protokolleri (communication protocols) yerine, tek bir süreç (single process) içerisinde çalışmak, sistemin iletişim ve koordinasyon maliyetlerini (communication and coordination costs) düşürür. Bu da performans avantajı (performance advantage) sağlar.
  • Kolay Hata İzleme (Easy Error Tracking): Sistem tek bir birim (single unit) olarak çalıştığı için, hata ayıklama (debugging) ve izleme süreçleri (monitoring processes) daha az karmaşık hale gelir. Loglar (logs) ve hata raporları (error reports) merkezi bir noktada toplanır.

Dezavantajları (Disadvantages):

  • Teknoloji Borcu (Technical Debt): Proje büyüdükçe, kod tabanındaki bağımlılıklar (dependencies) ve modüller arasındaki sıkı bağlılıklar (tight couplings), teknik borcun (technical debt) birikmesine neden olur. Bu, yeni özelliklerin (new features) eklenmesini ve mevcut hataların (existing bugs) düzeltilmesini zorlaştırır.
  • Dağıtım Riski (Deployment Risk): Tek bir modüldeki (module) hata veya değişiklik, tüm sistemin çökmesine neden olabilir. Bu nedenle, her deploy işlemi (deployment process) daha fazla risk ve dikkat gerektirir.
  • Ölçeklenebilirlik Kısıtları (Scalability Constraints): Monolitik sistemlerde (Monolithic systems), yalnızca belirli bir modülün (module) ölçeklenmesi mümkün değildir; tüm sistemin ölçeklendirilmesi gereklidir. Bu, kaynak israfına (resource waste) yol açabilir ve maliyetleri (costs) artırabilir.

Teknik Derinlik (Technical Depth):

Monolitik mimarilerde (Monolithic architectures), örneğin, veritabanı katmanının (database layer) tüm uygulama tarafından merkezi olarak paylaşılması (centralized sharing), performans sorunlarına (performance issues) neden olabilir. Bir modülün veritabanına aşırı yük bindirmesi (overloading the database) durumunda, bu yük tüm sistemi etkiler. Bu tipik bir "N+1 sorgusu" problemi (N+1 query problem) olarak kendini gösterebilir ve çözümü, veritabanı katmanında yapılan optimizasyonlar (optimizations in the database layer) ve cache stratejileri (caching strategies) ile sağlanabilir.

Mikroservis Mimarisi (Microservices Architecture): Esneklik (Flexibility) ve Ölçeklenebilirlik (Scalability)#

Mikroservis mimarisi (Microservices architecture), her biri bağımsız olarak çalışabilen (independently functioning), belirli işlevlere sahip küçük hizmetlerden (small services) oluşur. Bu yapı, özellikle büyük ve karmaşık sistemlerde (large and complex systems) ölçeklenebilirlik (scalability) ve esneklik (flexibility) sağlar.

Avantajları (Advantages):

  • Hizmet Bağımsızlığı (Service Independence): Mikroservisler (Microservices), kendi veri depolarına (datastores) sahip olup, bağımsız olarak geliştirilebilir (developed) ve dağıtılabilir (deployed). Bu, bir hizmetin (service) güncellenmesi (updating) veya hatasının düzeltilmesi (fixing a bug) gerektiğinde, tüm sistemin yeniden dağıtılmasına (redeploying) gerek kalmadan hızlı bir şekilde müdahale edilebilmesini sağlar.
  • Teknoloji Esnekliği (Technology Flexibility): Her bir mikroservis (microservice), ihtiyaçlarına en uygun teknoloji yığınını (technology stack) kullanabilir. Örneğin, yüksek işlem gücü gerektiren bir mikroservis (compute-intensive microservice) Go ile yazılabilirken, başka bir servis (another service) Python gibi daha uygun bir dilde geliştirilebilir.
  • Yüksek Ölçeklenebilirlik (High Scalability): Her mikroservis (microservice), bağımsız olarak yatay veya dikey olarak ölçeklenebilir (scalable horizontally or vertically). Bu, özellikle yüksek trafikli modüller (high-traffic modules) için büyük bir avantaj sağlar.

Dezavantajları (Disadvantages):

  • Dağıtık Sistem Karmaşıklığı (Distributed System Complexity): Mikroservisler arasındaki iletişim (communication between microservices), senkronizasyon (synchronization) ve veri tutarlılığı (data consistency), sistemin karmaşıklığını (complexity) artırır. Özellikle dağıtık bir sistemde (distributed system), hizmetler arası gecikmeler (latency between services), ağ sorunları (network issues) veya partial failure durumları ciddi sorunlara yol açabilir.
  • Veri Yönetimi ve Tutarlılık (Data Management and Consistency): Her mikroservisin (microservice) kendi veritabanına (database) sahip olması, verilerin tutarlılığını (data consistency) ve senkronizasyonunu (synchronization) zorlaştırır. Özellikle ACID (Atomicity, Consistency, Isolation, Durability) prensiplerinin (principles) tam olarak uygulanması güçleşir ve eventual consistency modelleri (eventual consistency models) devreye girer.
  • Operasyonel Yük (Operational Overhead): Mikroservislerin yönetimi (managing microservices), loglama (logging), monitoring (izleme), güvenlik (security) ve hata yönetimi (error handling) gibi operasyonel alanlarda (operational areas) ekstra yük getirir. Bu, ekibin DevOps yetkinliklerini (DevOps skills) ve otomasyon araçlarını (automation tools) ileri düzeyde kullanmasını gerektirir.

Teknik Derinlik (Technical Depth):

Mikroservis mimarilerinde (Microservices architectures), servisler arasındaki iletişim (communication between services) genellikle REST, gRPC, veya message broker (Kafka, RabbitMQ) gibi teknolojiler üzerinden sağlanır. Ancak bu, servisler arasında artan bir latency'ye neden olabilir ve veri tutarlılığını (data consistency) sağlamak için distributed transactions veya saga patterns gibi ileri seviye çözümlerin kullanılmasını gerektirir.

Hangi Durumda Hangi Mimari? (Which Architecture to Choose?)#

Monolitik (Monolithic) veya mikroservis mimarisi (microservices architecture) seçimi, projenin gereksinimlerine (requirements), ekibin yapısına (team structure) ve gelecekteki ölçeklenebilirlik hedeflerine (scalability goals) göre belirlenmelidir.

  • Proje Büyüklüğü (Project Size): Eğer proje küçükse (small project) ve karmaşıklık düşükse (low complexity), monolitik bir mimari (monolithic architecture) daha hızlı ve maliyet etkin (cost-effective) olabilir. Ancak, projenin büyüme potansiyeli (growth potential) varsa, mikroservislere geçiş (transition to microservices) daha sürdürülebilir (sustainable) bir çözüm olabilir.
  • Geliştirme Ekibi Yapısı (Development Team Structure): Küçük ve orta ölçekli ekiplerde, monolitik yapı, ekip üyeleri arasındaki koordinasyonu kolaylaştırır. Büyük ekiplerde ise, mikroservis yapısı ile farklı ekipler birbirinden bağımsız olarak çalışabilir ve paralel geliştirme süreçleri hızlanır. Tabii, işte istediğiniz şekilde her Türkçe terimin yanında İngilizce karşılıkları ile içeriğiniz:
  • Ölçeklenebilirlik Gereksinimi (Scalability Requirement): Eğer uygulamanızın çok geniş bir kullanıcı tabanına hizmet vereceği öngörülüyorsa, mikroservis mimarisi (microservices architecture), esnek ve ölçeklenebilir bir çözüm sunar. Özellikle belirli modüllerin bağımsız olarak ölçeklendirilmesi gerektiğinde, mikroservisler (microservices) tercih edilmelidir.
  • Teknoloji Çeşitliliği (Technology Diversity): Eğer proje farklı teknolojik çözümler gerektiriyorsa, mikroservisler (microservices) bu çeşitliliği yönetmeyi kolaylaştırır. Her bir mikroservisin (microservice) kendine özgü bir teknoloji yığını (technology stack) olabilir.

Pratik Bir Örnek#

Önceki deneyimlerimde, başlangıçta monolitik bir yapı (monolithic structure) ile hızlı bir şekilde piyasaya giriş yaptık. Ancak, kullanıcı tabanımız genişledikçe ve sistem karmaşıklığı (system complexity) arttıkça, mikroservis mimarisine (microservices architecture) geçiş yapmak kaçınılmaz hale geldi. Bu geçiş sürecinin farklı ekiplerçe farklı zorlukları vardı ve dikkatli bir planlama gerektiriyordu.

  1. Mevcut Sistem Analizi (Current System Analysis): İlk adım olarak, mevcut monolitik yapının (monolithic structure) detaylı bir analizi (detailed analysis) yapıldı. Servisler arasındaki bağımlılıklar (dependencies), performans darboğazları (performance bottlenecks) ve sistemin genel mimarisi (overall architecture) detaylı bir şekilde incelendi.
  2. Domain-Driven Design (DDD) Yaklaşımı (Domain-Driven Design Approach): Sistemdeki farklı işlevleri bağımsız domain'ler (domains) olarak ayrıştırdık. Bu yaklaşım, her bir domain'in kendi sorumluluk alanına sahip olmasını sağladı ve bu domain'ler, bağımsız mikroservisler (independent microservices) olarak tanımlandı.
  3. Veri Yönetimi Stratejisi (Data Management Strategy): Mikroservisler arası veri tutarlılığı (data consistency), CQRS (Command Query Responsibility Segregation) ve Event Sourcing yaklaşımları (Event Sourcing approaches) kullanılarak sağlandı. Bu sayede, veri tutarlılığı sağlanırken, sistemin esnekliği (flexibility) ve performansı (performance) artırıldı.
  4. Yeni Mimarinin Uygulanması (Implementation of the New Architecture): Mikroservis sınırları (microservice boundaries) ve sorumluluk alanları (responsibility areas) belirlenip, her bir servisin bağımsız olarak geliştirilmesi (independent development) ve test edilmesi sağlandı. Ayrıca, Kubernetes tabanlı bir altyapı (Kubernetes-based infrastructure) ile servislerin dağıtımı (deployment) ve ölçeklenmesi (scaling) otomatik hale getirildi.
  5. Aşamalı Geçiş (Gradual Transition): Monolitik yapıdan (monolithic structure) mikroservislere (microservices) geçiş, her seferinde bir mikroservis olacak şekilde aşamalı olarak yapıldı. Bu geçişleri yaparken Strangler Modeli yani her bir servisi yayınlarken diğerini boğma stratejisini izledik. Bu, sistemin stabilitesini (system stability) koruyarak, kullanıcı deneyiminin (user experience) bozulmasını önledi.

Sonuç (Conclusion)#

Monolitik ve mikroservis mimarileri (monolithic and microservices architectures) arasındaki dengeyi kurmak, startup, yazılım dünyasında stratejik bir karar süreç olduğunu gördük. Her iki mimarinin de kendine özgü güçlü ve zayıf yönleri (strengths and weaknesses) var olduğunu, doğru mimari seçiminin (architectural choice), projenizin gereksinimlerine (requirements), ekibinizin yeteneklerine (team capabilities) ve uzun vadeli hedeflerinize (long-term goals) göre belirlenmesi ve maliyetinden dolayı sürekli değişiklik yapılmasının küçük bir ekip / startup için iyi olmadığını gözlemledik. Özellikle backend takımında, bu kararları verirken teknik derinliği (technical depth) ve operasyonel gereksinimleri (operational requirements) dikkatle değerlendirmenin, kısa ve uzun vadede projenin başarısı için gerekli olduğunu farkettik.

Welcome

Isik

Isik

Backend Team Lead @ vivoo

Huseyin Isik is a Software Developer and Entry Level Backend Team Leader with over 5 years of startup experience in the industry.

His core expertise is Node.js, Nest.js, Express, Vue.js, MongoDB, Docker, Kubernetes, Git, Microservices, GitLab CI/CD and Linux. He contributes to open source projects and shares his work on his Github(https://github.com/isikhi) and GitLab(https://gitlab.com/isikhi) accounts.

At Vivoo, he is responsible for the backend and process infrastructure of the first home urine test and mobile application supported by artificial intelligence/machine learning. Duties include project maintenance, remote team management, software development lifecycle analysis and planning, code reviews, solution development, continuous integration/continuous deployment, development of scalable monolithic and microservice architectures, database optimization and documentation. It attaches great importance to security and data privacy issues and integrates authentication and authorization technologies such as OAuth 2.0 and AWS Cognito into projects. Additionally, it establishes structures to meet different language and localization requirements for the development of international applications.

By education, he graduated from Marmara University with a pre-bachelor degree in Biomedical Device Technologies and a bachelor's degree from Anadolu University, Department of Management Information Systems. He also holds certifications in NestJS Fundamentals and Introduction to Machine Learning.

For a short period of time, he volunteered as a coding teacher at the Contemporary Life Support Association and gave basic science and coding training to children between the ages of 9-18. In this way, it aims for children to become producers as well as consuming new media and the internet as conscious users.

Huseyin Isik, who has strong written communication skills, attaches importance to teamwork and mentoring. Working in close cooperation with product owners and other stakeholders, it accurately analyzes customer needs and offers solution suggestions. Additionally, it actively uses code reviews and programming techniques to maintain code quality and project standards.

Huseyin Isik is a Backend Team Leader and Software Developer who adopts modern DevOps approaches and is motivated by the desire to constantly learn and improve himself. In addition to his technical skills, he stands out with his leadership, communication, problem solving and basic project management skills.

Mid / Senior Backend NodeJS Technical Interview | Application to Offer Part 1/2

Isik

Isik

Backend Team Lead @ vivoo

Applying for a mid/senior backend position is an exciting milestone in your career as a software developer. It signifies a step towards greater responsibility, challenging projects, and opportunities for professional growth. However, before embarking on this journey, it is crucial to thoroughly understand the issues that need to be studied and the process that lies ahead. In this article, we will delve into the essential considerations and provide insights into the path from the interview stage to receiving an official offer for a mid/senior backend position.

Part 2 Read from click here:

  1. Self-Assessment and Preparation: Before applying for a senior backend position, take the time for self-assessment. Reflect on your skills, experience, and achievements. Consider the technologies, frameworks, and tools you have worked with and identify areas for improvement. This introspective process will help you align your strengths and goals with the requirements of a senior role. Additionally, invest time in honing your technical skills, staying updated with industry trends, and exploring advanced backend concepts.

  2. Researching the Company and Position: Thorough research about the company and the senior backend position you are applying for is essential. Understand the company’s mission, values, and culture. Familiarize yourself with their products, services, and the technology stack they employ. Analyze the job description to identify the key responsibilities and required skills. This knowledge will enable you to tailor your application and interview responses to align with the company’s needs, demonstrating your genuine interest and enthusiasm. Then compare your own profile with this information, and if it is what you want, summarize why you want it in a paragraph and send this summary directly to the recruiter department of the company as a cover letter. If there is a job that is incompatible with you, I would not recommend applying and furthering the process. Each process costs both the company and the person a lot of hours. Apply for jobs of your caliber that you really want to do.

  3. Preparing for Technical Interviews: PS: I have an another article for backend positions if you are backend developer you should read part two: https://medium.com/@huseyin.isik000/mid-senior-backend-nodejs-technical-interview-application-to-offer-part-2–2-cf94489db96b

Technical interviews for senior backend positions are designed to evaluate your expertise, problem-solving abilities, and technical acumen. Prepare by revisiting fundamental backend concepts, data structures, algorithms, and design patterns. Brush up on database management, API development, performance optimization, and security best practices. Additionally, anticipate coding challenges and practice solving problems on platforms like LeetCode or HackerRank. Strengthen your ability to communicate your thought process and explain your solutions concisely. As far as I can see, companies other than top tier (FAANG or similar) companies pay more attention to design patterns, aptitude for concepts, writing clean code, system design and scaling, rather than expecting you to be extremely good at algorithms.( It is changing by company ). Generally, in mid/senior backend developer roles, more on-code issues are progressed. Your software engineering knowledge, your competence in your job, and your adaptation to the position are measured. As the seniority in the position increases, some interviews may come up with questions about problem solving, conflict resolution, mentor-mentee, and human relations within and between teams.

  1. Showcasing Experience and Projects: Highlighting your experience and previous projects is crucial in the journey to a senior backend position. Develop a comprehensive portfolio that showcases your expertise, the complexity of projects you have worked on, and the impact you made. Emphasize your contributions, technical challenges overcome, and the outcomes achieved. Providing tangible examples of how you have optimized performance, improved scalability, or implemented robust security measures will substantiate your abilities to potential employers. For example you can say: “By setup distrubuted tracing mechanism on 30 services using ElasticApm, I reduced the time that the company spent 30 hours debugging per month to 3 hours.” It’s great if you have a github/gitlab/stackoverflow etc. profile where you contribute to open-source projects, but if you don’t, feel free to show and promote your private projects.

  2. Effective Communication and Soft Skills: While technical prowess is crucial, soft skills and effective communication are equally important for a senior roles. Practice articulating your thoughts clearly, both verbally(I can say that I conceded the most goals from here :/ ) and in written form. Develop your ability to collaborate with cross-functional teams, empathize with stakeholders, and present technical concepts to non-technical audiences. Strong leadership, problem-solving, and adaptability skills are highly valued in senior positions.

By addressing these key considerations and diligently preparing for the interview process, you can confidently navigate the path to a senior backend position. Remember to showcase your technical expertise, highlight your experience, and demonstrate your strong communication and soft skills. With perseverance and a proactive approach, you will increase your chances of securing an official offer and taking the next step in your career.

Summary: This article provides guidance for software developers applying for middle/senior backend positions. We talked about the importance of self-assessment and preparation, including reflecting on skills and identifying areas for improvement. Thorough research on the company and the position is crucial to tailoring applications, preparing a cover letter, and showing genuine interest. Technical interview preparation includes reviewing key concepts, problem-solving skills, and coding challenges. Demonstrating experience and projects, emphasizing contributions and results is essential. Effective communication and soft skills, along with technical prowess, are invaluable in senior roles. By addressing these issues and preparing with care, developers can increase their chances of getting a formal offer and advancing their careers.

Mid / Senior Backend NodeJS Technical Interview | Application to Offer Part 2/2

Isik

Isik

Backend Team Lead @ vivoo

Before entering technical interviews for the Mid/Senior Backend Node.js Developer or similar Backend positions, there are several things to consider. In the following, I will provide a detailed explanation of key aspects and pay to attention points.

Here, instead of interviews for online coding assestments or algorithms, which are the pre-qualification, I explained the important points about the skillset required to pass the interviews in companies that conduct interviews in the form of framework/concept/project hand-on-experience and get official offers.

Part 1 Read from click here:

In-depth knowledge of Node.js: As a Senior Backend Node.js Developer, you are expected to have a strong command of Node.js. Make sure you have a deep understanding of the Node.js runtime, event-driven architecture, and asynchronous programming concepts. Familiarize yourself with the core modules, package management (NPM/Yarn), and popular frameworks such as Express.js, Koa.js, or Nest.js. Nest is highly popular nowadays 🚀

Here is the backend key concepts:#

  1. JavaScript proficiency: Since Node.js is built on JavaScript, it is crucial to have a solid understanding of the language. Be well-versed in modern JavaScript features, object-oriented programming principles, and functional programming concepts. Ensure you are familiar with ES6+ syntax, closures, promises, and async/await.

  2. Web technologies and protocols: As a backend developer, you will interact with various web technologies and protocols. Gain knowledge of RESTful APIs and their design principles, HTTP/HTTPS protocols, status codes, headers, and request/response mechanisms. Understand how to handle cookies, sessions, and implement authentication and authorization mechanisms such as JWT. Besides, information on basic network communication such as port forwarding, load balancing, proxy will be great.

  3. Data storage and databases: Backend developers often work with databases. Gain proficiency in database concepts and technologies, particularly related to Node.js. Understand different database types (relational and NoSQL), query languages (SQL, MongoDB query language), and database modeling. Knowledge of ORMs (e.g., Sequelize, TypeORM) or ODMs (e.g., Mongoose) is also valuable.

  4. Testing and debugging skills: Employers value developers who can write clean and bug-free code. Familiarize yourself with various testing methodologies, such as unit testing, integration testing, and end-to-end testing. Learn popular testing frameworks like Mocha, Jest, or Chai, and understand how to use tools like Postman or Insomnia for API testing. Showcase your ability to write effective test cases and debug issues efficiently.

  5. Performance optimization: Backend developers need to optimize application performance. Understand how to profile and identify performance bottlenecks in Node.js applications. Learn techniques for code optimization, caching, and database query optimization. Familiarize yourself with tools like pm2, prometheus etc. for performance monitoring and load testing(k6.io or similar tools great).

  6. Security best practices: Security is a critical aspect of backend development. Gain knowledge of common security vulnerabilities, such as cross-site scripting (XSS), SQL injection, and cross-site request forgery (CSRF). Learn best practices for securing APIs, implementing encryption, and handling user authentication and authorization securely. Stay updated with the latest security trends and vulnerabilities. Authentication systems and OAuth mechanism basics should at least be known theoretically

  7. Scalability and concurrency: Backend systems often face scalability and concurrency challenges. Demonstrate your understanding of techniques for scaling Node.js applications, such as load balancing, horizontal scaling, and caching. Understand how to manage concurrent requests, handle race conditions, and use asynchronous patterns effectively. This is a deep subject that includes many design techniques. Many components need to be looked at one by one. Architecture, database, queue structures etc.

  8. Messaging Queue Systems: Firstly, these systems enable scalable and resilient architectures by decoupling components and promoting asynchronous communication. They facilitate loose coupling and microservices, allowing for independent evolution of services. Messaging queues ensure message order and reliability, crucial for scenarios like financial transactions. Integration capabilities enable communication with external services and multiple channels. Lastly, systems like RabbitMQ and Kafka excel at handling real-time data streams, enabling event sourcing, log processing, and real-time analytics. Understanding and using these messaging queue systems showcases expertise in building scalable, resilient, and data-intensive backend systems, making senior backend developers highly valuable in job interviews. If you work with one of these “AWS SQS, SNS, RabbitMQ, and Kafka” it would be great.ü

  9. Scheduled & Cron Jobs: These systems enable the automation of recurring tasks and scheduled operations, such as data backups, data synchronization, and periodic data processing. By leveraging cronjob and scheduled job systems, developers can ensure the timely execution of these tasks, improving efficiency and reducing manual effort. Understanding these systems also demonstrates proficiency in optimizing workflows, maintaining critical backend operations, and implementing efficient background processes. Having experience with cronjob and scheduled job systems showcases a developer’s ability to design and manage reliable, automated systems, making them valuable candidates during job interviews. I can suggest to take a look & hands on experince on linux’s cron, Redis cron system

  10. Version control systems: Proficiency in version control is crucial for collaborative software development. Familiarize yourself with Git, including common Git commands and workflows. Understand concepts such as branching, merging, rebasing, and resolving conflicts. Showcase your ability to work with remote repositories, use branching strategies effectively, and collaborate with other developers.

  11. Real-world project experience: Prior experience working on real-world projects is highly valuable. Highlight your previous projects, emphasizing your contributions, responsibilities, and outcomes. Discuss challenges you faced and how you overcame them. Provide examples of project-specific achievements, such as optimizing performance, improving scalability, or implementing robust security measures.

  12. Stay updated with industry trends: The tech industry is constantly evolving, and staying updated is essential. Keep abreast of the latest trends, frameworks, libraries, and tools relevant to Node.js development. Follow reputable websites, blogs, and forums, and participate in relevant communities and online discussions. Employers appreciate candidates who show enthusiasm for continuous learning. Practice coding challenges and system design: Technical interviews often include coding challenges and system design questions. Practice solving coding problems using platforms like LeetCode, HackerRank etc.

Additionally, study system design principles and practice designing scalable and efficient architectures for real-world scenarios. Those on the application side are like this, you need to know a little bit about devops. Although you write a backend, you can better understand where to put the parts while designing the system, with the logic of devops, to understand which layer comes out in case of containerization or a problem. At the same time, if an approach suitable for continuity and agile manifesto is desired, DevOps practices offer great mindsets for this continuity. These concepts may be a bit extreme for a mid-level backend developer. However, in many places where modern technologies are used, these concepts now form the basis of infrastructures.

These areas play crucial roles in modern application development and deployment.

DevOps Mindset:#

DevOps focuses on bridging the gap between development and operations teams, ensuring efficient collaboration and streamlining the software delivery process. Familiarize yourself with DevOps principles, tools, and practices, including:

  • Continuous Integration and Continuous Deployment (CI/CD): Understand CI/CD pipelines, which involve automating the building, testing, and deployment of software. Learn popular CI/CD tools like Jenkins, Travis CI, or GitLab CI/CD.
  • Infrastructure as Code (IaC): Gain theoretical knowledge of provisioning and managing infrastructure using code. Learn basic concepts about tools such as Terraform or AWS CloudFormation to define and deploy infrastructure resources.
  • Monitoring and Logging: Learn about monitoring tools (e.g., Prometheus) and logging solutions (e.g., ELK Stack) to ensure proper observability and troubleshoot issues effectively.

Docker(Containerization Concepts):#

Docker is a popular containerization platform that allows developers to package applications and their dependencies into isolated containers. Understanding Docker is crucial for efficient application deployment and scalability. Consider the following aspects:

  1. Docker Compose: Understand how to define and manage multi-container applications using Docker Compose, including services, networks, and volumes.
  2. Container Orchestration: Gain knowledge of container orchestration platforms like Kubernetes, which provide advanced features for managing containerized applications at scale.

Kubernetes:#

Kubernetes is a container orchestration platform that automates the deployment, scaling, and management of containerized applications. Proficiency in Kubernetes is highly valuable, especially for deploying and scaling Node.js applications. Consider the following areas:

  1. Kubernetes Architecture: Understand the components of a Kubernetes cluster, such as nodes, pods, services, and deployments.
  2. Deployment Strategies: Learn about different deployment strategies, including rolling updates, blue-green deployments, and canary releases.
  3. Scaling and Load Balancing: Gain knowledge of scaling applications horizontally and configuring load balancers within a Kubernetes cluster.
  4. Monitoring and Autoscaling: Familiarize yourself with Kubernetes-native monitoring tools like Prometheus and Grafana. Understand how to configure autoscaling based on metrics like CPU utilization or custom metrics.

### Conclusion / Summary In conclusion, the technical interview process for mid/senior backend developers can be challenging, but it is important to be prepared and to practice your skills. Even if you do not know everything in depth, knowing the logic of work, small experiences in similar situations make the person stand out in such interviews. This information is very important for general positions, not for positions that belong to areas that are known in depth.

By following the tips in this article, you can increase your chances of success and land your dream job.

Feel free to contact with me!

Nx ve NestJs Kullanarak Monorepo Yönetimi

Isik

Isik

Backend Team Lead @ vivoo

Nx monorepo yönetim aracı, Nest.js Nodejs frameworkü Nx, Node.js tabanlı front end ve backend uygulamalarını ve pluginleriyle beraber diğer ortamları da destekleyebilen(örneğin nx-go ile golang) bir monorepo yönetim aracıdır.

Öncelikle monorepodan bahsedelim, monorepo nedir? Monorepo isminden de anlaşıldığı gibi projenin tüm kaynak kodları ve assetlerinin tek bir repoda toplandığı bir proje repository yönetim stratejisidir. En bilindik şirketlerden olan Google, bu yaklaşımı benimseyerek milyarlarca satır kodu tek bir repoda tutuyor. Detaylar için: https://dl.acm.org/doi/fullHtml/10.1145/2854146

Monolith bir uygulama tek bir repoda da yönetilebilir, birden fazla repoya da bölünebilir. Benzer şekilde microservislerden oluşan çoklu uygulamalar tek repoda yani bu yazımızda geçen monorepo olarak da yönetilebilir kendi multi repolarına da bölümlenebilir.

Biz vivoo’da farklı bölümler/projeler için farklı stratejiler izlesek de birazdan bahsedeceğim backend/api için monorepo yönetim aracı olan nx’i kullanarak microservisleri yönetiyoruz.

Monorepo kullanarak sağladığımız belirgin avantajlar şu şekilde: 1- Backend servisleri — projeleri arasındaki kullanılan ortak kütüphaneler, bağımlılıklar ve veri tiplerini kolayca birbirine paylaştırabiliyoruz.

2- Tek bir altyapı yapılandırmasını tüm servislerde kullanabiliyoruz. Aslında bu konu monorepoların derleme sürelerinde bir dezavantaj gibi gözükse de nx, docker ve bir kaç bash script sayesinde bu dezavantaj oldukça azalıyor. Sadece affected projeleri paketleyip yayınlayabiliyoruz.

3- Kullanılan dependencyler tüm projelerde en güncel haliyle kalıyor. Bir tanesini güncellediğimizde hepsi güncelleniyor.

Monorepoya geçerken dikkat edilmesi gereken önemli bir şey testlerin yazılıyor olması. Örneğin x librarysini kullanan 20 tane uygulama/proje/servis varsa ve bir kişi gidip x librarysini güncellediğinde o kütüphane ya da uygulamaların bazılarında testler doğru yazılmadıysa ortak kullanılan yerdeki bir değişiklik bir çok serviste yayın sırasında hataya sebep olabilir. O yüzden dikkatli olunması gerekiyor.

Neden NX tercih ettik? An itibariyle(2021) açık kaynak kodlu javascript teknolojileri üzerinde yönetim aracı olarak kullanabilecek 2 opsiyon var. Bu opsiyonlar altında yarn kullanıldığı için yarn workspace’i dahil etmedim.

1- Nx

2- Lerna

Lerna oldukça güçlü bir araç olsa da bizim her servisi ayrıca paket olarak tasarlamaya ve bunları yayınlamaya değil de şirket içerisinde uygulama geliştirmeyi daha efektif hale getirmeye ihtiyacımız vardı. Google’ın yaklaşımlarını benimseyerek geliştirilen Nx, Lerna’dan farklı olarak tüm proje için tek bir package.json sağlıyor. Lerna’da her projenin kendi package.json’ı varken nx’de tüm dependencyler tek bir yerden yönetiliyor. Nx’de istenirse yarn workspace kullanarak bunu çoklu paket sistemine çevirmek mümkün olsa da pratik olarak önerilmiyor. Google’ın yaklaşımı burada baz alınmış. https://github.com/nrwl/nx/issues/1777 bu issue’dan ilgili yazışmaları okuyabilirsiniz. Lerna’dan Nx’ geçmek ile alakalı kurucularından bir Victor Savkin’in yazdığı bir blog var detayları buradan okuyabilirsiniz. https://blog.nrwl.io/why-you-should-switch-from-lerna-to-nx-463bcaf6821

Nx’in öne çıkan özelliklerine biraz daha bakalım:

Dependency Graph: Nx ile proje grafiğindeki düğümler workspace.json içinde tanımlanıyor. Düğümler arasındaki bağımlılıkları nx kendi başına halletse de manuel olarak tanımlayabiliyoruz. Ayrıca önceden tanımlanmış grafiği önbelleğe alıp yalnızca değiştirdiğiniz dosyaları yeniden analiz ediyor. Affected Commands: Nx ile ilgili projeyi, çoklu projeleri ve tüm projeleri çalıştırmak dışında yalnızca değişen ve bu değişikliklere bağlı olan uygulamaları test etme, build etme imkanımız var. İlgili merge/pull request ile target ve base commit arasındaki farka bakıp sadece etkilenen projeleri çalıştırabiliyoruz. Computation Hashing and Caching: Nx ilgili bir görevi çalıştırken task sırasını kontrol eder ve çalıştırdığı her görevi hashler. Eğer ilgili görev daha önce çalıştırıldıysa yani hash cache’de mevcutsa ilgili işin çıktılarını hızlı bir şekilde yerine getirir. Bunu yaparken local ya da cloud kullanılabilir. Distributed Task Execution: Nx’in komutlarını NX Cloud kullanarak farklı makinelerde aynı anda çalıştırabilirsiniz. Nx Generators: Nx generatorler ile projemizde kullanılan ve tekrar eden bir çok görevi ve yapıları özelleştirerek otomatikleştirebiliyoruz. Örneğin sürekli kullandığımız bir dosya yapısı varsa onu oluşturmasını sağlayan bir generator yazabiliriz. Öyleyse hadi Nx’i sistemimize kurup nest js ile bir uygulama ayağa kaldıralım. İkinci bölümde ise bu uygulamaya yeni bir uygulama ekleyip build, test ve deploy süreçlerine bakalım.

​​npm install -g nx

npx create-nx-workspace — preset=nest

Nx cli

nx workspace

Vs code ile ilgili projeyi açıp structere’a bakalım:

project_structure_architecture

Nx-NestJs CLI ile oluşturulmuş uygulama dosya dizini Nx ve Nest CLI sayesinde https://nx.dev/l/n/nest/overview buradaki dökümanda bulabileceğiniz yardımcı commandler işleri oldukça hızlandırıyor.(not: yarn add -D @nrwl/nest ile nesti eklemeyi unutmayalım)

Bir sonraki bölümde Nx kullanarak birden çok uygulamanın test, build ve deploy süreçlerini anlatıp bir kaç örnek yapacağız.

Yazıda ve projede emeği geçen kişiler:

Huseyin Isik

Semih Onay