Bu yazımda bilgisayar mühendisliği eğitimi alırsanız neleri öğreneceğinizin kısa bir özetini geçeceğim. Yazmayı düşünüyorsanız en azından neyle karşılaşacağınızı bilin.

Oldukça kompakt bir bilgisayar mühendisliği anlatımı içermektedir bu yazı. Halihazırda okuyanlar da yararlanabilir.

Bizim okulun ders programından hareketle yazacağım ama her okulun müfredatı %80 aynıdır. Zaman olursa bir müfredat karşılaştırması da yaparım.

Müfredat

Bilgisayar mühendisliği dersi olmayan dersleri kısa geçiyorum.

Önemli not: Terimlerin Türkçelerini kullanmıyorum. Birinci nedeni: hangilerinin kullanıldığını bilmiyorum, ikincisi önem arzetmiyor, üçüncüsü garip duruyor ve gündelik kelimelerle karışıyor, İngilizcesi'ni kullanınca onun terim olduğunu hemen anlıyorsunuz. Yine de İngilizce Türkçe karışık kullanacağım işime geldiği gibi.

1. Sınıf 1. Dönem


ENG101 (İngilizce 101): Bu derste resmi bir dil kullanarak akademik makale yazmayı öğrenirsiniz. Kuralları basittir, kurallara uymayanlar ağır cezalandırılır. Okulun en zor derslerinden biridir ilginç olarak. Sadece derste okutulan kaynakları kullanmanıza izin vardır, dolayısıyla bu makaleleri iyi okuyup çıkarım yapabilmeniz gerekir ki makale yazabilesiniz.

TURK101 (Türkçe 101): Kitap okuyup blog yazısı yazarsınız bu derste özellikle. Bizim iki haftada bir kitap okumamız gerekiyordu, ben kitaplara bir göz atıp bir tema belirleyip yazıyordum.

MATH101 (Calculus): Türev integral

MBG110 (Biyoloji): Temel lise biyolojisi: hücrenin yapısı, bölümleri, bölünmesi, evrim (mutasyon, adaptasyon, doğal seleksiyon vs. Lisede adamakıllı eğitim verilmediği için evrim bunlardan bağımsız ayrı bir şeymiş gibi bir algı oluşuyor.) Bu dersin verilmesinin asıl nedeni ABET kriterlerine göre birkaç tane temel bilim dersi üniversitelerde okutulmalıdır. Bizim okulda diğer okullarının aksine Kimya gibi gereksiz bir ders yerine biyoloji seçmiştir. Biyoloji Bioinformatik gibi bilgisayar alt alanlarında çalışacakların işine yarayabilir. (Bu alt alanlarda aşırı bir Biyoloji bilgisi gerekmemektedir.)

CS101: Programlama ve Algoritmalara Giriş


Aslında bunu bu yazıda yazmıştım. Ama kısaca üzerinden geçeyim.

Bizim okulda Java, ODTÜ'de C, Singapur'da Python, herhangi bir dil kullanılarak öğrencilere temel programlama eğitimi verilir. Amaç dili öğretmek değildir. Dilin özelliklerinden de biraz bahsedilse de bu dersteki problemleri başka bir dili kullanarak da çözebilirsiniz.

Temel İşlemler

Önce şu öğretilir:

int elmaSayısı = 5.

Bu bir "assignment" (atama) ifadesidir. elmaSayısı diye bir değişken (variable, matematiktenin aynısı) yaratırsınız, bu değişken tam sayı yani integer tutacak dersiniz ve içine 5 sayısını koyarsınız. Artık bir yere elmaSayısı yazarsanız aslında elmaSayısı'nın tuttuğu değeri kullanmış olursunuz, bu durumda bu 5'tir. Örneğin int armutSayısı =  elmaSayısı + 5 derseniz armutSayısı 10 tutmuş olur.

Yarattığınız (daha doğrusu tanımladığınız) değişkenler sadece tek bir tip değer tutar, karakter derseniz karakter, kesirli sayı derseniz kesirli sayı. Bunun mantığını isterseniz kendiniz okuyabilirsiniz ama kesin olarak ikinci senede öğrenirsiniz.

Tabii sadece atama yok, toplama çıkarma felan da var.

int elmaSayısı = 5 + 103212231038103;

Bu durumda bilgisayar önce 5 ile o malum sayıyı toplar, sonra çıkan sayıyı elmaSayısına atar.

Sonra size "if-else" (eğer, şartlı ifade) ve loop (döngü) öğretirler.

if-else = Bu buysa bunu yap, yoksa bunu yap. Örnek: elma sayım 5 ise armut sayımı 10 yap.

int armutSayısı;
if (elmaSayısı == 5)
    armutSayısı = 10;
else
    armutSayısı = 2309138012;

elmaSayısı == 5 demek elmaSayısı'nın içinde 5 mi var? demek. 5 varsa true değerini döner, bu da 1,2, 5 gibi bir değerdir. yoksa false döner.

Canınız isterse içinde doğru veya yanlış tutan bir değişken de tanımlayabilirsiniz yani. Bu tip değere "Boolean" denir. (George Bool bulmuş bunu, kendi adını koymuş.)

boolean elmalarımÇürükmü = 5;

Not: Önce armutSayısı diye bir değişken tanımlamak gerekiyor. Bu değişkeni if-else'in içinde tanımlarsanız sadece if-else'in altında yaşar, dışında çalışmaz. Neden böyle olduğunu üçüncü sınıfta anlatıyorlar, ben de o zaman anlatayım. ;'nın mantığı da aynı şekilde üçüncü sınıfta.

loop = Bunu şu olana kadar tekrarla. Armut sayım 5'e düşene kadar armutlarımı azalt. while, for, do while loopları vardır javada. While'ı yazayım.

== eşit mi? demekti ya, != ise eşit değil mi? demek.

int armutSayısı = 10;
while (armutSayısı != 5)
  armutSayısı = armutSayısı - 1;

if-else ve while sadece doğru mu yanlış mı onu çek edebilir, eğer siz doğru mu yanlış mı sorusunu soran bir işlem koymazsanız parantez içine, bilgisayar da bunu "doğru herhalde bu" diye okur ve kafasına göre takılır. Dolayısıyla siz if (elmaSayısı = 5) yazarsanız bilgisayar bunu elmaSayısı'nı 5 yap sonra takıl diye algılar. Hoca da tüm cevabınızı çizer. Dersten kalırsınız.

Diziler:

Dizi yani "array" (bazı dillerde list) demek önceden belirlenmiş sayıda değeri sırayla tutan eleman.

Örneğin ben 5 tane sayı tutacağım bir yerde, dizi yaratıyorum. Java'da şöyle yaratılır.

int[] kiminKaçElmasıVar = {2, 5, 10}

int[] demek int dizisi demek.

Böylelikle üç kişinin kaç elması olduğunu kiminKaçElmasıVar dizisinde tuttum. Birinci kişinin 2, ikinci kişinin 5 tane var.

Programlama dillerinin bir çoğunda saymaya 0'dan başlanır. Birinci kişinin elmaSayısına erişmek için kiminKaçElmasıVar[0] yazmalısınız.

int ahmetinElmalar = kiminKaçElmasıVar[0] derseniz ahmetinElmalar diye bir değişken yaratıp bu değişkenin içinde önceki yarattığımız dizinin birinci elemanının elma sayısını tutmuş olursunuz.

Eğer bir dizi yaratmak istiyorsanız ama sayıları önceden belirlemek istemiyorsanız şöyle bir ifade kullanmanız gerek:

int[] elmaSayısı = new int[3];

new nereden çıktı? Az sonra.

Buraya kadar anlattığım kısmı anladıysanız tebrikler! Basit mülakat sorularını çözebilecek hale geldiniz. Hatta buradan problem çözebilirsiniz bile. (Tabii daha fazla "incelik" öğrenmeniz gerek ben şu an kısa özet geçiyorum)

Fonksiyonlar:

Fonksiyonlar, (javacılar method der buna) bildiğimiz Matematikteki fonksiyonlardır. Bütün kodu bir sayfaya yazmak istemediğinizde veya başkasının kodunu kullanacağınız zaman veya daha başka zamanlar kullanırsınız. f(x) = x + 5. Diye bir fonksiyon yaratırsınız. f(elmaSayısı) diye yazarsanız aslında elmaSayısı + 5 yazmış olursunuz.

Java'da bir method şu şekilde yazılır.

public static int karesiNe (int değişken) {
    return değişken * değişken;
}

* çarpma işlemidir.

Bu fonksiyon verilen değişkenin karesini alıp geri verir.

int fonksiyonun döneceği değer. { ve } fonksiyonun tanımını çevreler ki kod başka şeylerle karışmasın. return ise geri verme ifadesi. "Üstte naparsan yap, bana fonksiyon ne çıkaracak onu söyle." demek yani.

Ayrıca fonksiyonların içini bilmeden de kullanabilirsiniz ki zaten genelde öyle yapacaksınız. Bir çok yazılımcı bir problem karşısında ne yapacağını bilir ama yapacağı şeyi sıfırdan yazmaz. Örneğin benim elimde bir sürü rakam var bunları sıralayacağım, bunları sıralamanın on farklı şekli var ben Quicksort yönteminin en iyi olduğunu biliyorum çünkü en süper benim, ama gidip Quicksort yazmama gerek yok. Javada hazır olarak yazılmıştır zaten, o yazılan fonksiyonu kullanırım olur biter. Quicksort nedir sonra anlatacağım.

Nesne Yönelimli Programlama

Buraya kadar her şey çok güzeldi ama nesne yönelimli programlama konsepti ve genel olarak "Obje" konsepti işleri biraz karıştırıyor.

Şimdi; şu ana kadar öğrendiğimiz tip değerler "Primitive" yani ilkel değerlerdi. Ben int elmaSayısı dediğim zaman bilgisayar kendi içinde belirlediği büyüklükte bir tam sayı kadar hafıza açar, 32 bit bilgisayarda bu değer iki milyar. elmaSayısı'nın içine - iki milyar ile + iki milyar arasında herhangi bir sayı yerleştirebiliriz.

Fakat ya istediğimiz büyüklükte sayı dizileri ve diğer ıvırzıvırlar yaratmak istiyorsak? İşte şimdi devreye objeler giriyor.

Objeler olmasaydı herhalde şöyle şöyle aptal aptal şeylerle uğraşırdık:

ikiTaneİnt elmaSayıları = 1, 2

üçTaneİnt elmaSayıları = 1,2, 5

dokuzYüzOnBinTaneİnt elmaSayıları = mavi ekran

Bu olmasın diye boyutunu önceden tanımlayabildiğiniz yani önceden ne tuttuğunu belirleyebildiğiniz objeler ortaya çıkmış.

örneğin ben bir GidenAraba objesi tanımlıyorum. Giden arabanın hızı var, maksimum hızı var bir de tekerlek sayısı var, malım tekerlek sayısını tutacağım. Önce böyle bir objeyi yaratacak taslak / şablon / blueprint / model bilmemne isminde bir şey tanımlıyoruz ki bu tanımladığımız şeyle bir sürü GidenAraba objesi tanımlayabilelim. Buna javada "Class" (sınıf) deniyor. Böyle tanımlanıyor:

Not: // demek not düşmek demek, // 'dan sonra aynı satırda gelen kısım bilgisayar tarafından okunmaz, siz okursunuz sadece.

public class GidenAraba {
   final int TEKERLEK_SAYISI = 4; // Ya ne olacağdı?
   int arabanınHızı = 60;
   int arabanınMaksimumHızı = 180;
   int bagajdakiElmaSayısı = 10; // O elma yenecek arkadaş :D
}

final int ne? Final demek sabit (örneğin fizikteki Coulomb sabiti) demek. Bir arabanın tekerlek sayısı 4 olduğundan (pırpır şirketinde yazılımcı değilseniz tabii) ve değişmeyeceğinden ben bunu "Sabit" olarak belirledim, programın bir yerinde değişirse bilgisayar hata verir bak burada sabiti değiştirmeye çalışmışın ayıp oluyo diye. Bu tür kod yazma incelikleri mevcut evet.

Şimdi ne yaptık biz? İçinde dört tane tam sayı tutan bir obje yapmış olduk.

Artık dilediğimiz gibi GidenAraba objesi yaratıp istediğimiz gibi kullanabiliriz.

GidenAraba ahmetinArabası = new GidenAraba()

Ama bu yaptığımız şey hiçbir işe yaramaz. Neden? Çünkü bütün yarattığımız gidenArabalar aynı olur.

O yüzden "constructor" denen özel fonksiyonları tanımlamamız gerekir ki değişik GidenArabalar yaratabilelim.

Bu da fonksiyon yapmanın aynısı, sadece return yok, bir şey return edilmiyor çünkü.

public GidenAraba (int gidenArabanınHızı) {
   arabanınHızı = gidenArabanınHızı;
}

Parantez içine daha fazla değişken de koyabiliriz ama üşendim şimdi.

Yaptığımız Class son olarak böyle oldu:

public class GidenAraba {
   final int TEKERLEK_SAYISI = 4; // Ya ne olacağdı?
   int arabanınHızı = 60;
   int arabanınMaksimumHızı = 180;
   int bagajdakiElmaSayısı = 10; // O elma yenecek arkadaş :D

  public GidenAraba (int gidenArabanınHızı) {
      arabanınHızı = gidenArabanınHızı;
  }

}

Böyle bir tane araba oluşturalım.

GidenAraba ahmetinArabası = new GidenAraba(80);

Böylelikle 80 km/h'de giden bir arabamız oldu. (Gerçi km/h mi m/s mi onu belirlemedik henüz.)

İstersek objenin içindeki değişkenlere erişebiliriz.

int ahmetinElmaSayısı = ahmetinArabası.bagajdakiElmaSayısı;

Şimdi buradaki new "Yeni bir araba yap." demek. İsteseydim Ahmet'in arabasını ara ara kullanan Mehmet için de bir GidenAraba objesi tanımlardım ama Mehmet'in arabasıyla Ahmet'in arabası aynı olduğu için Mehmet'in arabası değişkeni de aynı objeyi tutmuş olurdu.

GidenAraba mehmetinArabası = ahmetinArabası

İşte şimdi başka bir zurnanın zırt dediği yere geldik, birinci sınıflar için zor olan bir konsepte.

int elmaSayısı = 5 dediğim zaman elmaSayısı direkt olarak 5 sayısını tutarken ahmetinArabası, ahmetinArabasını tutmaz, ahmetinArabası objesinin adresini tutar. Böylece o obje birden fazla şekilde çağrılacağı zaman tekrar tekrar yeni obje (bu durumda yeni araba) yaratmamıza gerek kalmaz.

Yani şu:

GidenAraba ahmetinArabası = new GidenAraba(80);
GidenAraba mehmetinArabası = ahmetinArabası;
GidenAraba mehmetinAbisininArabası = ahmetinArabası; // mehmet abisi ahmet
GidenAraba ronaldonunYüzüneBakmayacağıDandikAraba = ahmetinArabası;

Bu durumda elimizde sadece tek bir araba ve o arabaya "işaret eden" dört tane değişken olur. Hepsinin içinde de o arabanın adresi yazılıdır.

Bu durumda araba değişirse ona işaret eden tüm değişkenler de aynı değişikliği tanımış olur.

Örneğin biz ahmetinArabası.arabanınHızı = 0; dedik araba durdu.
Bu durumda mehmetinArabası.arabanınHızı da 0 olur.

Eğer ortalık malı olmuş bu arabayı programdan silersek tüm değişkenler arabasız kalır.

Eğer ikinci araba yapıp Mehmet'e vermek istersek özel işlemler yapmalıyız. Gereksiz yere yazıyı uzatacağı ve başka programlama dillerinde farklılık göstereceği için bunu anlatmayacağım. Merak eden java için .clone() metodunu araştırsın.

Classlara özel fonksiyonlar koyduğumuz gibi normal fonksiyonlar da koyabiliyoruz! Örneğin bir GidenAraba'nın tekerleklerinin hızının toplamını hesaplayayım ve söyleyeyim. Niye bunu yapıyorum, çünkü hava çok sıcak burada ve canım sıkıldı.

public int tekerleklerinHızıToplamı() {
    return arabanınHızı * TEKERLEK_SAYISI;
}

Class'ın son hali: 

public class GidenAraba {
   final int TEKERLEK_SAYISI = 4; // Ya ne olacağdı?
   int arabanınHızı = 60;
   int arabanınMaksimumHızı = 180;
   int bagajdakiElmaSayısı = 10; // O elma yenecek arkadaş :D

  public GidenAraba (int gidenArabanınHızı) {
      arabanınHızı = gidenArabanınHızı;
  }

  public int tekerleklerinHızıToplamı() {
      return arabanınHızı * TEKERLEK_SAYISI;
  }

}

Bu fonksiyon her obje için farklı olduğu için anca objenin yanında . koyup çağırabiliriz.

int hız = ahmetinArabası.tekerleklerinHızıToplamı();

Önceki fonksiyondaki static neydi? Bir Class'ın içine fonksiyon yazarsak o fonksiyon dinamik olur ve her obje için farklı sonuçlar döner, ne de olsa ahmetinArabasıyla benim arabam aynı hızda gitmiyor olabilir. static dersek objeye bağlı olmaz özetle. (Class'a bağlı olup classın default değerlerini kullanır.)

Peki public ne? Eğer değişken ve fonksiyonları public değil private tanımlarsak o tanımadığımız şeye sadece yaşadığı yerden erişebiliriz. Örneğin private int bagajdakiElmaSayısı deseydik sonra başka yerde ahmetinArabaSayısı.bagajdakiElmaSayısı diyemezdik, kod hata verirdi. Bu kısımlar çok önemli değil.

Javada Arrayler yani diziler de objedir!  Yani

int[] elmaSayıları = new int[5] derseniz içinde 5 elma sayısı olan bir obje yaratmış olursunuz ayrıca bu arrayin uzunluğu içine "length" değişkeninde kaydolur, yani elmaSayıları.length derseniz 5 sayısını elde ederseniz.

Java'da String dediğimiz harf bütünlüğü de objedir!

String selam = "Naberlen" yazarsanız içinde 8 tane karakter olan bir objeniz olmuş olur. (Bu ifade aslında String selam = new String("Naberlen") dir ama java yapımcıları bunu kısaltmıştır haliyle) selam içinde 8 tane karakter olan objenin adresini tutar.

String selam = "Naber" yazarsanız içinde "Naberlen" yazan obje silinir, yeni obje oluşturulur. Yani ahmetinAraba gider ronaldonunAraba gelir farzı misal. Stringler bu özelliğinden dolayı zor yazılı sorularına gebedir, iyi çalışılması gerekir.

Nesne yönelimli programlar yazılım mühendisliğinin temelidir. Büyük şirketlerin büyük kodu olur ve görev paylaşımı düzenli olmak zorundadır dolayısıyla nesne yönetimi iyi yapılmalıdır. Her şeyi birbirine karıştıran dandik mühendisler bu yüzden tercih edilmez. Üniversitelerde "Nesne Yönelimli Yazılım Mühendisliği" dersi okutulur ki öğrenciler nesne yönetiminin tekniklerini öğrensin ve işlerinde uygulasın. (Bu ders üçüncü sınıfta, daha oraya geleceğiz.)

Programlamayı sadece simulasyon için kullanacak Elektronikçi, Makineci ve Endüstriciler hatta tüm bölümler buraya kadar anlattığım kısmın eğitimini alır (ve iyi öğrenmek zorundadır!) fakat sonra nesne yönetimi kısmına devam etmez.

Algoritmalar

Bu giriş dersinde bir de algoritmalardan bahsedilir ama detaylı bilgi verilmez o yüzden sonra bahsedeceğim.

Tebrikler birinci sınıf birinci dönemi bitirdiniz! Sadece bunları bilirseniz dersten pek iyi alamazsınız, ucundan geçersiniz. Ama bu anlattıklarım çok iyi bir giriştir.

Birinci sınıf ikinci dönemde görüşmek üzere, tabii ben bu detayda yazmaya devam ederseniz hepsi yetişecek mi bilmiyorum.