Ana içeriğe geç

2026 İçin En İyi 30 Scala Mülakat Sorusu ve Cevabı

Scala bilgisi gerektiren bir işe mi başvuruyorsunuz? İş görüşmenizde öne çıkmanızı sağlayacak temel, orta ve ileri düzey Scala sorularını keşfedin!
Maria Eugenia Inzaugarat
Maria Eugenia Inzaugarat

Ücretsiz Hesabınızı Oluşturun

Alıştırma and program your progress.

Google ile devam edinDevam ederek, Kullanım Koşullarımızı ve Gizlilik Politikamızı kabul etmiş ve verilerinizin ABD'de saklandığını onaylamış olursunuz.

Scala, fonksiyonel ve nesne yönelimli programlamayı harmanlayan güçlü bir dildir. Kısa ve öz sözdizimi, ölçeklenebilirliği ve performans avantajları sayesinde büyük veri işleme ve web uygulamalarında yaygın olarak kullanılır. 

Veri endüstrisinde Scala uzmanlığına olan talep artarken, bu makale temel kavramlardan ileri tekniklere ve veri mühendisliği sorularına kadar çeşitli konuları kapsayan kapsamlı bir Scala mülakat soruları rehberi sunacaktır.

Temel Scala Mülakat Soruları

Bu güçlü dilin çekirdek kavramları ve avantajlarına ilişkin anlayışınızı ölçen bazı temel Scala mülakat sorularını inceleyerek başlayalım.

Dile yeniyseniz, mülakat sorularına geçmeden önce sağlam bir temel oluşturmak için r Scala'ya Giriş kursuyla başlayın.

Scala nedir ve Java'dan nasıl farklıdır?

Scala adı, scalable (ölçeklenebilir) kelimesinden gelir. Scala, nesne yönelimli ve fonksiyonel programlama paradigmalarını birleştiren, statik olarak türlenen bir programlama dilidir. Kısa ve öz, ifade gücü yüksektir ve Java'nın birçok eksikliğini gidermek üzere tasarlanmıştır. Örneğin, Scala Java Sanal Makinesi (JVM) üzerinde çalışır; bu da Java kütüphane ve çerçevelerini sorunsuzca kullanabileceğiniz anlamına gelir.

Java kesinlikle nesne yönelimliyken, Scala hem nesne yönelimli hem de fonksiyonel programlamaya olanak tanır. Scala; değişmezlik, üst düzey fonksiyonlar, desen eşleme ve daha fazlası gibi gelişmiş özellikleri, hepsini kısa ve öz bir sözdizimiyle sunar.

Eğer Java geçmişiniz varsa, temel bilgileri tazelemek için he Java'ya Giriş kursuna göz atın. Java ve Scala'da nesne yönelimli prensipleri karşılaştırmak için Java'da OOP'ye Giriş kursunu deneyin.

Scala'nın temel özellikleri nelerdir?

Scala'yı öne çıkaran ve geliştiriciler arasında popüler kılan güçlü özellikleri vardır. İşte bunlardan bazıları:

  • Tür çıkarımıyla birlikte statik türleme. Scala statik olarak türlenen bir dildir; bu, türlerin derleme anında kontrol edilerek tür güvenliği sağlandığı anlamına gelir. Scala'nın gelişmiş tür çıkarım sistemi sayesinde çoğu durumda değişken ve fonksiyonların türlerini açıkça belirtmeniz gerekmez. Derleyici türleri otomatik olarak çıkarabilir.
  • Fonksiyonel programlama desteği. Scala, fonksiyonel programlamayı birinci sınıf olarak destekler. Fonksiyonları birinci sınıf değerler olarak ele almanıza, argüman olarak geçirmenize ve diğer fonksiyonlardan döndürmenize olanak tanır. Değişmezlik temel bir kavramdır ve değişmez koleksiyonlar varsayılandır. Scala ayrıca üst düzey fonksiyonları destekleyerek daha soyut ve yeniden kullanılabilir kod yazmayı mümkün kılar.
  • Java ile birlikte çalışabilirlik. Scala JVM üzerinde çalışır; bu da Java koduyla kesintisiz entegrasyona olanak tanır. Bu, Java kütüphane ve çerçevelerini doğrudan Scala kodu içinde kullanabileceğiniz ve tersinin de geçerli olduğu anlamına gelir. Scala Java kodunu çağırabilir, Java da Scala bileşenleriyle etkileşime girebilir; bu da mevcut Java projeleriyle son derece uyumlu ve çok yönlü olmasını sağlar.
  • Kısa ve öz sözdizimi. Scala, Java'ya kıyasla gereksiz ayrıntıyı azaltmak üzere tasarlanmıştır; bu da onu daha ifadeli ve özlü kılar. Geliştiricilerin daha az şablon koduyla daha temiz ve okunabilir kod yazmasına olanak tanır. İsteğe bağlı parantezler, tür çıkarımı ve özlü kontrol yapıları gibi özellikler, Scala'yı Java'ya göre yazmayı ve bakımını daha kolay hâle getirirken ifade gücünü tam olarak korur.
  • Desen eşleme. Scala'nın desen eşleme özelliği, karmaşık veri yapılarıyla çalışmayı basitleştiren güçlü ve esnek bir özelliktir. Türleri, değerleri ve yapıları eşleştirmenize olanak tanır; bu da birden fazla if-else ya da switch ifadesi ihtiyacını ortadan kaldırabilir. Özellikle karmaşık veri kalıplarıyla uğraşırken kodu daha özlü, okunabilir ve bakımı kolay hâle getirir.
  • Aktör tabanlı eşzamanlılık modeli. Scala, Akka çerçevesiyle popülerleşen aktör tabanlı model aracılığıyla eşzamanlılığı yönetmek için yerleşik araçlar sunar. Bu model, hesaplamayı mesajlaşma yoluyla iletişim kuran bağımsız "aktörlere" ayırarak son derece eşzamanlı, dağıtık ve hata toleranslı sistemler oluşturmanıza olanak tanır. Bu yaklaşım, durumu yönetmeyi basitleştirir ve geleneksel iş parçacığı tabanlı eşzamanlılık modellerinin tuzaklarından kaçınır; bu da Scala'yı ölçeklenebilir ve dayanıklı uygulamalar geliştirmek için ideal kılar.

Geliştiriciler arasında Scala'nın başarısının arkasındaki temel özellikler

Scala'da case class nedir ve neden kullanılır?

Scala'da case class, değişmez veri yapılarıyla kullanım için optimize edilmiş özel bir sınıftır. toString, equals ve hashCode gibi yöntemlerin uygulamalarını otomatik olarak sağlar. Case class'lar ayrıca desen eşlemeye elverişlidir ve bu da verileri fonksiyonel bir tarzda ele almak için son derece kullanışlıdır.

Genellikle, oluşturulduktan sonra değişmemesi gereken veri nesnelerini temsil etmek için case class'lar kullanılır. Aşağıya bir örnek bıraktım: 

case class Person(name: String, age: Int)
val person1 = Person("John", 30)

Scala değişmezliği nasıl ele alır?

Scala'da, özellikle fonksiyonel programlama için değişmezlik teşvik edilir. Değişmez bir değişkeni var yerine val kullanarak bildirebilirsiniz; var değiştirilebilirken val değiştirilemez. Bir val'e değer atadıktan sonra değiştirilemez. Değişmezlik, istenmeyen yan etkiler için daha az alan bıraktığından daha güvenli ve öngörülebilir koda yol açar. Aşağıdaki örneğime bakın:

val name = "Alice"

// Değerini değiştirmeye çalışmak derleme zamanı hatasına yol açar
name = "Bob"  // Hata: val'e yeniden atama

Scala'da companion object'ler nedir?

Companion object, bir sınıfla aynı ada sahip olan ve aynı dosyada tanımlanan nesnedir. Companion object'in temel amacı, sınıfla yakından ilişkili olup o sınıfın bir örneğine bağlı olmayan yöntem ve fonksiyonlar sağlamaktır.

Companion object, fabrika metodları veya diğer yardımcı fonksiyonları barındırabilir; aşağıda yazdığım örnekte olduğu gibi:

class Person(val name: String, val age: Int)
object Person {
  def apply(name: String, age: Int): Person = new Person(name, age)
}

Person companion object'indeki apply metodu, aşağıda gösterdiğim gibi new anahtar sözcüğünü kullanmadan bir Person oluşturmama olanak tanır:

val p = Person("John", 25)

Scala'da var, val ve lazy val arasındaki fark nedir?

var, val ve lazy val anahtar sözcükleri Scala'da değişken tanımlamak için kullanılır; ancak değiştirilebilirlik, başlatma ve değerlendirme zamanlaması açısından farklılık gösterir. 

var, başlatıldıktan sonra değeri değiştirilebilen, değiştirilebilir bir değişkendir. Bir var'a yeni bir değer atayabilirsiniz:

var x = 10
x = 20  // Yeniden atanabilir

Öte yandan, val değiştirilemez bir başvuru türüdür; yani bir kez değer atandığında yeniden atanamaz, ancak başvurduğu nesne yine de değiştirilebilir olabilir

val y = 10
// y = 20  // Hata: val'e yeniden atama

lazy val, ilk kez erişilene kadar değerlendirilmeyen özel bir val türüdür; buna tembel değerlendirme denir. Bu, maliyetli veya kaynak yoğun hesaplamalarla çalışırken performans optimizasyonu için yararlı olabilir.

lazy val z = {
  println("Computing z")
  42
}

Scala'da değişken bildirimleri ve en iyi uygulamalar hakkında daha derin bir bakış için bu Scala'da Değişkenler öğreticisine göz atın.

Scala'da üst düzey fonksiyonlar (higher-order functions) kavramını açıklayabilir misiniz?

Scala'da üst düzey bir fonksiyon, parametre olarak bir veya daha fazla fonksiyon alan ya da sonuç olarak bir fonksiyon döndüren fonksiyondur. Bu kavram, fonksiyonların birinci sınıf değerler olarak ele alınmasına olanak tanır ve kodunuzda daha fazla esneklik ve soyutlama sağlar. 

Üst düzey fonksiyonlar, davranışların aktarılmasına ve özelleştirilmesine imkân tanıyarak kodu daha modüler, yeniden kullanılabilir ve ifade gücü yüksek hâle getirir. 

Aşağıya, başka bir fonksiyonu argüman olarak kabul eden bir üst düzey fonksiyon örneği bıraktım:

// Parametre olarak bir fonksiyon alan üst düzey fonksiyon tanımlayın
def applyFunction(f: Int => Int, x: Int): Int = f(x)

// Girdiyi 2 ile çarpan bir fonksiyonla üst düzey fonksiyonu çağırın
val result = applyFunction(x => x * 2, 5)  // 10

Bu durumda, applyFunction 2 ile çarpan bir f fonksiyonunu alır ve 5'e uygular.

Scala'da String ve StringBuilder arasındaki fark nedir?

Scala'da String değişmezdir; yani yapılan değişiklikler yeni nesneler oluşturur ve bu da tekrarlanan değişiklikler için verimsiz olabilir. Seyrek dize işlemleri için uygundur. 

Buna karşılık, StringBuilder değiştirilebilirdir ve yeni nesneler oluşturmadan yerinde değişikliklere izin verir. Bu, ekleme veya içeriği değiştirme gibi sık dize işlemleri için daha verimli olmasını sağlar. 

Değişmezliğin tercih edildiği ve performansın kritik olmadığı durumlarda String, çoklu dize değişikliklerinin söz konusu olduğu senaryolarda daha iyi performans gerektiğinde ise StringBuilder kullanmanızı öneririm.

Scala'da @tailrec açıklayıcısının amacı nedir?

@tailrec açıklayıcısı, özyinelemeli çağrının metodun içindeki son işlem olduğu, yani kuyruk özyinelemeli bir metodu işaretlemek için kullanılır. Bu, Scala derleyicisinin metodu, özyinelemeyi döngüye dönüştürerek yığın taşması hatalarını önleyecek şekilde optimize etmesine olanak tanır. Metot kuyruk özyinelemeli değilse derleyici hata verir.

Bir örnek görelim:

@tailrec
def factorial(n: Int, accumulator: Int = 1): Int = {
  if (n <= 0) accumulator
  else factorial(n - 1, n * accumulator)
}

Orta Seviye Scala Mülakat Soruları

Temelleri ele aldıktan sonra, dilin nasıl çalıştığını daha iyi anlamanıza yardımcı olacak orta seviye Scala mülakat sorularına geçelim.

Scala'da map, flatMap ve foreach arasındaki fark nedir?

Scala'da map, flatMap ve foreach koleksiyonlar üzerinde kullanılan üst düzey fonksiyonlardır, ancak farklı amaçlara hizmet ederler. 

  • map, bir koleksiyonun her öğesini dönüştürür ve dönüştürülmüş öğelerle aynı boyutta yeni bir koleksiyon döndürür. 
  • Buna karşılık, flatMap de her öğeyi dönüştürür, ancak ortaya çıkan yapıyı düzleştirir; bu, dönüşümün kendisinin koleksiyonlar ürettiği durumlarda kullanışlıdır. 
  • Son olarak, foreach yan etkiler için kullanılır; hiçbir şey döndürmeden her öğeye bir fonksiyon uygular ve genellikle yazdırma veya haricî durumları güncelleme gibi işlemlerde kullanılır.

Scala'da desen eşleme (pattern matching) nedir ve kullanım alanları nelerdir?

Scala'da desen eşleme, değerleri desenlere göre eşleştirmenizi sağlayan güçlü bir özelliktir; kodu daha ifadeli ve özlü hâle getirir. Diğer dillerdeki switch veya case ifadelerine benzer; ancak daha esnektir ve tamsayılar, dizgeler, listeler ve hatta karmaşık veri yapıları gibi çeşitli türlerle kullanılabilir. match ifadeleriyle, bir ifadenin değerini birden çok desenle karşılaştırmak için kullanılabilir.

Desen eşlemenin bazı kullanım alanları şunlardır:

  1. Farklı veri türlerini ele alma: Bir sınıf hiyerarşisinde veya ayrık birleşimlerde (sealed trait'ler) belirli türlere göre eşleme.
  2. Veri yapılarının ayrıştırılması: Case class'larda eşleme, değerlerin çıkarılması veya veri içeriğine dayalı işlemler.
  3. Option ile çalışma: Option içinde Some veya None değerlerini kontrol ederek boş olabilecek değerleri özlü biçimde ele alma.
  4. Liste ve demet (tuple) ayrıştırma: Listelerin, demetlerin veya dizilerin öğeleri üzerinde eşleme yaparak kolay çıkarım ve işleme.

İşte bir örnek: 

// Değeri 3 olan bir x değişkeni tanımlayın
val x = 3

// x'in değeri üzerinde desen eşleme
x match {
  // 'x' 1'e eşitse "One" yazdır
  case 1 => println("One")
    // 'x' 2'ye eşitse "Two" yazdır
  case 2 => println("Two")
  // 'x' yukarıdaki durumların hiçbirine uymuyorsa "Other" yazdır
  case _ => println("Other")
}

Scala'da Option, Some ve None'ın amacı nedir?

Scala'da Option, bir değerin var olabileceğini ya da olmayabileceğini temsil eden bir kapsayıcı türdür ve null değerlerini ve null pointer hatalarını önlemeye yardımcı olur. İki alt türe sahiptir: Some ve None. 

Some geçerli bir değeri sarmalayarak değerin mevcut olduğunu belirtirken, None değerin yokluğunu ifade eder. Bu, geliştiricilerin bir değerin eksik olabileceği durumları açıkça ele almasına imkân tanır ve daha güvenli, daha fonksiyonel kodu teşvik eder. 

Option, sonuç döndüremeyebilen yöntemlerde sıklıkla kullanılır ve hataya açık null kontrollerinin gerekliliğini azaltır.

Aşağıdaki koda bakın:

// Bir Option döndüren fonksiyon
def findFirstEvenNumber(list: List[Int]): Option[Int] = {
  list.find(_ % 2 == 0)  // Çift bir sayı bulunursa Some(number), aksi takdirde None döner
}

// Örnek kullanım:
val numbers = List(1, 3, 5, 7, 8)
val result = findFirstEvenNumber(numbers)
result match {
  case Some(number) => println(s"Found an even number: $number")  // Çıktı: Found an even number: 8
  case None => println("No even number found")
}

Scala koleksiyonları nasıl ele alır ve başlıca koleksiyon türleri nelerdir?

Scala, değiştirilebilir ve değiştirilemez olarak kategorize edilen zengin bir koleksiyon kümesi sunar. 

  • Değiştirilemez koleksiyonlar olan List, Set, Map ve Vector oluşturulduktan sonra değiştirilemez; bu da fonksiyonel programlama uygulamalarını teşvik eder.
  • ArrayBuffer, HashSet ve HashMap gibi değiştirilebilir koleksiyonlar değişikliklere izin verir. 

Koleksiyonlar, filtreleme, eşleme (mapping) ve katlama (folding) gibi çeşitli işlemleri destekleyen son derece esnek yapılardır. Standart kütüphane, farklı veri işleme ihtiyaçlarına verimli şekilde hitap eden Queue, Stack ve SortedSet gibi özelleşmiş koleksiyonlar da sunar. İş parçacığı güvenliği ve fonksiyonel saflık için değiştirilemez koleksiyonlar tercih edilir.

Scala'da örtük (implicit) parametreler kavramını açıklayabilir misiniz?

Scala'da örtük parametreler, bir metot ya da kurucuya derleyicinin açıkça belirtilmeden otomatik olarak geçirdiği değerlerdir. implicit anahtar sözcüğü ile işaretlenirler ve genellikle bağımlılık enjeksiyonu, yapılandırma veya bağlam aktarımı gibi amaçlarla kullanılırlar.

// String türünde örtük bir 'name' parametresi alan bir fonksiyon tanımlayın
def greet(implicit name: String) = s"Hello, $name"

// Kapsamda String türünde örtük bir 'myName' değeri tanımlayın
implicit val myName = "Alice"

// 'name'i açıkça geçmeden greet fonksiyonunu çağırın
// Derleyici, örtük değer 'myName'i otomatik olarak kullanır
println(greet)  // Çıktı: "Hello, Alice"

Scala'da trait'ler nedir ve Java'daki arayüzlerden (interface) nasıl farklıdır?

Scala'da trait'ler, Java'daki interface'lere benzer ancak ek yeteneklere sahiptir. Trait, sınıflara veya diğer trait'lere karıştırılabilen (mix-in) yeniden kullanılabilir bir bileşendir. Hem soyut metotlar hem de somut metotlar tanımlamanıza izin verir. Trait'ler, yalnızca metot imzaları tanımlayabilen Java arayüzlerinin aksine durum (state) da barındırabilir. 

Scala, bir sınıfa birden çok trait karıştırmayı destekler ve çoklu kalıtımı mümkün kılar; Java ise birden fazla arayüzü uygulamaya izin verirken yalnızca tek bir sınıftan kalıtım almaya izin verir ve kalıtım esnekliğini sınırlar.

İşte bir örnek:

trait Logger {
  def log(message: String): Unit = println(s"Log: $message")
}

Scala REPL (Read-Eval-Print Loop) nasıl çalışır?

Scala REPL, Scala kodunu gerçek zamanlı olarak yazıp değerlendirmenizi sağlayan etkileşimli bir kabuktur. Dört adımda çalışır:

  1. Read: REPL, kullanıcının Scala kodunu okur.
  2. Eval: Girdiyi derleyip çalıştırarak değerlendirir.
  3. Print: Değerlendirmenin sonucunu konsola yazdırır.
  4. Loop: Süreç tekrarlanır ve kodla sürekli etkileşim kurulmasını sağlar.

Bu süreç, Scala kodunu hızlıca deneyip test etmenizi sağlar ve Scala'da öğrenme, hata ayıklama ve prototipleme için güçlü bir araçtır. Değişkenler ve fonksiyonlar tanımlayabilir, kütüphaneleri etkileşimli olarak keşfedebilirsiniz.

Scala REPL arayüzünü gösteren, kullanılan Scala sürümünü belirten ve kullanıcının yazmasını bekleyen bir görüntü.

Şekil: Scala REPL, Scala kodunuzu test etmek için kullanabileceğiniz bir komut satırı yorumlayıcısıdır; bir oyun alanı gibidir. Kaynak: Scala dokümanları

İleri Düzey Scala Mülakat Soruları

Daha kıdemli rolleri hedefleyen veya Scala'ya daha derinlemesine hâkimiyetini göstermek isteyenler için, eşzamanlı olmayan hesaplamaların ve eşzamanlılığın ele alınmasının yanı sıra karmaşık yapı ve dönüşümlere değinen ileri seviye mülakat sorularını inceleyelim. 

Bu sorular, fonksiyonel programlama, eşzamanlılık ve ölçeklenebilir sistem tasarımı konularındaki uzmanlığınızı ölçecektir.

Scala'da Future ve Await arasındaki fark nedir?

Scala'da Future ve Await, eşzamanlı olmayan hesaplamaları ele almakla ilgili olup farklı amaçlara hizmet eder. 

  • Future, sonucuyla ya da bir istisna ile sonunda tamamlanacak bir hesaplamayı temsil eder. Hesaplamanın sonucu beklenirken diğer işlerin devam etmesine izin verir. 
  • Await, bir Future'ın sonucu hazır olana kadar geçerli iş parçacığını bloke etmek için kullanılır. Bir iş parçacığını bir Future'ın tamamlanmasını beklemeye zorlar. Genellikle eşzamanlı olmayan olmayan bir bağlamda sonuç için senkron bir şekilde beklemeniz gerektiğinde kullanılır.

Bu işlevlerin nasıl kullanılacağına dair bazı örnekleri burada gösteriyorum:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Await
import scala.concurrent.duration._

val futureValue = Future { 42 } // Değeri 42 olan bir Future'ı eşzamanlı olmayan şekilde hesaplar.
val result = Await.result(futureValue, 2.seconds) // Future'ın sonucunu beklerken iş parçacığını en fazla 2 saniye bloke eder.

Scala eşzamanlılığı nasıl ele alır ve yaygın olarak hangi kütüphaneler kullanılır?

Scala, iş parçacıkları gibi düşük seviyeli mekanizmaların yanı sıra eşzamanlı olmayan programlama için Future ve Promise gibi yüksek seviyeli soyutlamalar kullanarak eşzamanlılığı ele alır.

Standart kütüphane, engellemeyen hesaplamalar için scala.concurrent.Future'ı ve yürütme iş parçacıklarını yönetmek için ExecutionContext'i içerir.

Daha gelişmiş eşzamanlılık için, Aktör modelini kullanan yüksek derecede eşzamanlı ve dağıtık sistemler inşa etmeye yönelik araçlar sağlayan Akka yaygın olarak kullanılır. Ek olarak, Cats Effect ve ZIO gibi kütüphaneler, eşzamanlılığı ele almak için fonksiyonel programlama yaklaşımları sunarak yan etkiler, eşzamanlı olmayan görevler ve kaynakları yönetmek için güvenli, birleştirilebilir soyutlamalar sağlar.

Scala'da monad kavramını açıklayabilir ve bir örnek verebilir misiniz?

Monad'lar, özellikle eşzamanlı olmayan işlemler veya boş olabilen değerler gibi yan etkilerle uğraşırken hesaplamaları yapılandırılmış bir şekilde ele almak için kullanılan bir tasarım kalıbıdır. Monad, bir değeri sarmalamanın ve yapıyı korurken dönüşümler uygulamanın bir yolunu sağlar. Scala'da Option ve Future monad örnekleridir.

val result = Some(5).flatMap(x => Some(x * 2))

Dağıtık sistemler kurmak için Akka çerçevesi Scala ile nasıl çalışır?

Scala'daki Akka çerçevesi, dağıtık, eşzamanlı ve hata toleranslı sistemler oluşturmayı basitleştirmek için tasarlanmıştır. Aktör modelini kullanır; burada her aktör, mesajlaşma yoluyla eşzamanlı olarak iletişim kuran, hafif ve bağımsız bir birimdir. 

Akka, düşük seviyeli eşzamanlılık ayrıntılarını soyutlayarak geliştiricilerin iş mantığına odaklanmasını sağlar. Aktörlerin farklı düğümlerde çalışmasına imkân tanıyarak dağıtık sistemleri destekler. Akka'nın Cluster modülü, sorunsuz iletişim, yük dengeleme ve dayanıklılık sağlar; bu da onu ölçeklenebilir, yüksek erişilebilirlikte sistemler için ideal kılar.

Scala'da örtük dönüşümler (implicit conversions) nedir ve nasıl çalışır?

Scala'da örtük dönüşümler, bir türün otomatik olarak başka bir türe dönüştürülmesine izin verir. implicit anahtar sözcüğü kullanılarak tanımlanırlar ve normalde uyumlu olmayan türler arasında işlemleri etkinleştirmek için kullanılırlar. Derleyici, gerektiğinde örtük dönüşümleri uygular ve şablon kodunu azaltır. 

Örneğin, aritmetik işlemler yapılırken bir String'in otomatik olarak bir Int'e dönüştürülmesini nasıl yapabileceğinizi gösteriyorum: 

implicit def intToString(x: Int): String = x.toString
val str: String = 42  // Örtük olarak “42”ye dönüştürülür

Scala'da tür varyansı (+, -, ve =) nedir?

Scala'da tür varyansı, generik bir türün alt türlerinin birbirleriyle nasıl ilişkilendirildiğini ifade eder. Eşkovaryant (+), karşı-kovaryant (-) ve değişmez (=) tür parametreleri kullanılarak kontrol edilir.

  • Eşkovaryant (+): Bir tür eşkovaryant ise, tür parametresi yerine alt tür geçebilir. Örneğin, List[+A], List'in A türü, A'nın bir üst türünün beklendiği her yerde kullanılabilir anlamına gelir. Örnek: Dog, Animal'ı genişletiyorsa List[Dog], List[Animal] olarak kullanılabilir.
  • Karşı-kovaryant (-): Karşı-kovaryant bir tür, tür parametresi yerine bir üst türün geçmesine izin verir. Örneğin, Function1[-A, +B], bir Function1'in A'nın bir üst türünü kabul edip B'nin bir alt türünü döndürebileceği anlamına gelir. Örnek: Function1[Animal, Dog], Function1[Dog, Dog] olarak kullanılabilir.
  • Değişmez (=): Tür sabittir ve alt türleri veya üst türleriyle değiştirilemez. Örneğin, List[A] değişmezdir; List[Dog] ile List[Animal] birbirinin yerine kullanılamaz.

Veri Mühendisleri için Scala Mülakat Soruları

Bir veri mühendisliği pozisyonu için mülakata giriyorsanız, üretim ortamında Scala uygulamaları tasarlama, optimize etme ve sorun giderme yeteneğinizi ölçen sorular bekleyin. Karşılaşabileceğiniz bazı tipik mülakat sorularına değinelim.

Scala'da özel (custom) açıklayıcılar (annotation) nasıl tanımlanır ve kullanılır?

Scala'da özel bir açıklayıcı tanımlamak için scala.annotation.Annotation'ı genişleten bir sınıf oluşturmanız gerekir. Bu sınıf, meta verileri saklamak için kurucu parametreleri alır. Açıklayıcılar daha sonra @sembol ile sınıflara, yöntemlere veya alanlara uygulanır. 

Açıklayıcılarla ilgili faydalı bulduğum bir özellik de, özel açıklayıcıların meta verilerini almak için çalışma zamanında yansıma (reflection) yoluyla, genellikle getAnnotations veya benzeri yöntemlerle erişilebilir olmasıdır. 

import scala.annotation.StaticAnnotation
class MyAnnotation extends StaticAnnotation
@MyAnnotation class MyClass

Büyük veri işleme için Scala, Apache Spark ile nasıl kullanılır?

Scala, Apache Spark için yerel dildir ve sorunsuz entegrasyon ile yüksek performans sunar. 

RDD'ler (Resilient Distributed Datasets), DataFrame'ler ve Dataset'ler gibi Spark'ın çekirdek özelliklerinden yararlanarak dağıtık veri işleme işleri yazmak için kullanılır. Scala ile büyük veri kümeleri oluşturabilir ve işleyebilir, dönüşümler uygulayabilir ve bir küme genelinde karmaşık işlemleri verimli bir şekilde yürütebilirsiniz.

Spark'ın Scala API'si, toplu işlemeden makine öğrenmesi hatlarına kadar büyük veri görevlerini ele almak için kısa ve ifadeli bir sözdizimi sunar; paralel olarak geniş ölçekli veri analizi ve işleme sağlar.

PySpark'ı sıfırdan öğrenmek de ilginizi çekebilir—bu PySpark'a kapsamlı rehber başlamak için harika bir yer.

Spark'ta Scala ile RDD, DataFrame ve Dataset arasındaki fark nedir?

Spark'ta RDD'ler (Resilient Distributed Datasets) dağıtık veriyi temsil eden düşük seviyeli soyutlamalardır ve paralel olarak üzerinde işlem yapılabilir. DataFrame'ler ise RDD'lerin üzerine inşa edilen daha yüksek seviyeli soyutlamalardır; Spark'ın Catalyst iyileştiricisini kullanarak yapılandırılmış veri işleme ve optimize edilmiş yürütme sunar. 

Dataset'ler, RDD'lerin tür güvenliğini DataFrame'lerin optimizasyonlarıyla birleştirir. Dataset'ler güçlü tür denetimine sahiptir; DataFrame'ler ise türsüzdür ve Spark'ta daha verimli dönüşüm ve eylemlere olanak tanır.

Scala ile temel bir Spark işi (job) nasıl yazılır?

Temel bir Spark işi şunları içerir:

  1. SparkSession'ın başlatılması.
  2. Verinin bir RDD, DataFrame veya Dataset'e oluşturulması ya da yüklenmesi.
  3. Bu veri üzerinde dönüşümler ve eylemler gerçekleştirilmesi.
  4. İşin bir Spark kümesinde çalıştırılması.

Burada bir örnek görebilirsiniz:

// Spark SQL için giriş noktası olan SparkSession sınıfını içe aktarın
import org.apache.spark.sql.SparkSession

// Bir SparkSession oluşturun.
val spark = SparkSession.builder.appName("MySparkApp").getOrCreate()

// Girdi metin dosyasını bir DataFrame olarak okuyun.
val data = spark.read.text("data.txt")

// Metin dosyası üzerinde dönüşüm gerçekleştirin
val wordCount = textFile.flatMap(_.split(" ")).groupByKey(identity).count()
wordCount.show()

Spark'ta dönüşümler ve eylemler (transformations ve actions) nedir ve Scala'da nasıl uygulanır?

Spark'ta dönüşümler, map(), filter() veya groupBy() gibi yeni bir RDD, DataFrame veya Dataset tanımlayan işlemlerdir. Tembel değerlendirme ile çalışırlar; yani bir eylem tetiklenene kadar yürütülmezler. 

Eylemler, collect(), count() veya save() gibi yürütmeyi tetikleyen işlemlerdir. Dönüşümler veriye tembel olarak uygulanırken, eylemler Spark'ın operasyon DAG'ini yürütmesini ve bir sonuç döndürmesini ya da veriyi kalıcılaştırmasını zorlar.

Scala ile Spark'ta tembel değerlendirmenin önemi nedir?

Spark'ta tembel değerlendirme, dönüşümlerin hemen yürütülmediği anlamına gelir. Bunun yerine Spark bir yürütme planı (DAG) oluşturur ve hesaplamaları yalnızca bir eylem çağrıldığında çalıştırır. Bu, verinin yer değiştirmesini (shuffling) en aza indirerek, işlemleri birleştirerek ve filtreleri işleme hattının daha erken aşamalarında uygulayarak yürütmenin optimize edilmesini sağlar. 

Scala ile yazılmış Spark işlerini nasıl optimize edersiniz?

Spark işlerini optimize etmek; veri karıştırmayı (shuffle) en aza indirmek, ara sonuçları önbelleğe almak ve uygun bölümlemeyi (partitioning) kullanmak gibi çeşitli stratejileri içerir.

Spark işlerini optimize etmek için önereceğim bazı stratejiler şunlardır:

  • Spark'ın Catalyst sorgu iyileştiricisinden yararlanmak için RDD'ler yerine DataFrame/Dataset kullanmak. 
  • Uygun yerlerde önbelleğe alma kullanmak.
  • Veriyi karıştıran geniş dönüşümlerden (groupBy gibi) kaçınmak.
  • Büyük veri kümelerinin karıştırılmasını önlemek için yayın (broadcast) birleştirmeleri kullanmak.
  • Bölüm sayısını ayarlamak veya filtre itme (filter pushdown) kullanmak gibi Spark yapılandırmasını ayarlamak.

Scala'yı büyük veri projelerinde kullanırken karşılaştığınız yaygın zorluklar nelerdir?

Büyük veri projelerinde Scala ile yaygın zorluklar arasında büyük veri kümeleri için bellek ve performansı yönetmek, veri dengesizliğiyle başa çıkmak ve dağıtık ortamlarda hataları verimli şekilde ele almak yer alır. 

Spark işlerinde hata ayıklamak, dağıtık sistemlerin karmaşıklığı ve tembel değerlendirme nedeniyle zor olabilir. Ayrıca, darboğazlardan kaçınmak ve yükü azaltmak için Spark işlerini optimize etmek çoğu zaman yapılandırmaların ince ayarını ve altta yatan yürütme planının anlaşılmasını gerektirir. 

Ayrıca tutarsız veri biçimleri, veri kalitesi sorunları ve ölçeklenebilir kod yazma ve bakımının karmaşıklığı da büyük veri senaryolarında zorlayıcı olabilir.

Sonuç

Bu makalede, temel, orta ve ileri seviyeleri kapsayan geniş bir Scala mülakat soruları yelpazesini ele aldık. Scala'nın temel kavramları ve avantajlarını anlamaktan daha karmaşık optimizasyon, işleme ve dönüşümlere dalmaya kadar, potansiyel işverenlerin sorabileceği başlıca alanları inceledik.

Hazırlığınızı pekiştirmek için Scala'ya Giriş kursumuzla pratik yapmaya başlayın veya hızlı bir hatırlatma yapın! Çift Java-Scala rolüne mi hazırlanıyorsunuz? Tüm resmi görmek için Java mülakat soruları rehberimizi kaçırmayın.

Maria Eugenia Inzaugarat

Yazar

Maria Eugenia Inzaugarat

Konular

İlgili