Derin++ Derinlik

C++ Dil Eğitimi

Bu eğitimin ilk bölümlerinde son iki modülde halihazırda sunulan temel materyaller ele almakta ve ileri düzey kavramlar hakkında daha fazla bilgi verilmektedir. Bu modüldeki odağımız, dinamik bellek ve nesneler ile sınıflar hakkında daha ayrıntılıdır. Devralma, polimorfizm, şablonlar, istisnalar ve ad alanları gibi bazı ileri düzey konular da kullanıma sunuldu. Bunları daha sonra İleri Düzey C++ kursunda inceleyeceğiz.

Nesne Odaklı Tasarım

Bu, nesne odaklı tasarımla ilgili mükemmel bir eğiticidir. Bu modüldeki projesinde burada sunulan metodolojiyi uygulayacağız.

3. Örnekle Öğrenin

Bu modülde işaretçiler, nesne odaklı tasarım, çok boyutlu diziler ve sınıflar/nesneler ile ilgili daha fazla alıştırma yapmaya odaklanıyoruz. Aşağıdaki örnekleri inceleyin. İyi bir programcı olmanın sırrının pratik, pratik ve pratik olduğunu ne kadar vurgulasak azdır.

1. Alıştırma: İşaretçilerle Daha Fazla Alıştırma

İşaretçilerle ilgili daha fazla alıştırma yapmanız gerekiyorsa işaretçilerin tüm yönlerini kapsayan ve birçok program örneği içeren bu kaynağı okuyun.

Aşağıdaki programın sonucu ne oldu? Lütfen programı çalıştırmayın ancak çıkışı belirlemek için bellek resmini çizin.

void Unknown(int *p, int num);
void HardToFollow(int *p, int q, int *num);

void Unknown(int *p, int num) {
  int *q;

  q = #
  *p = *q + 2;
  num = 7;
}

void HardToFollow(int *p, int q, int *num) {
  *p = q + *num;
  *num = q;
  num = p;
  p = &q;
  Unknown(num, *p);
}

main() {
  int *q;
  int trouble[3];

  trouble[0] = 1;
  q = &trouble[1];
  *q = 2;
  trouble[2] = 3;

  HardToFollow(q, trouble[0], &trouble[2]);
  Unknown(&trouble[0], *q);

  cout << *q << " " << trouble[0] << " " << trouble[2];
}

Çıktıyı elle belirledikten sonra, doğru olup olmadığınızı görmek için programı çalıştırın.

2. Alıştırma: Sınıflar ve Nesnelerle Daha Fazla Alıştırma

Sınıflar ve nesneler hakkında daha fazla alıştırma yapmanız gerekiyorsa iki küçük sınıfın uygulanmasıyla ilgili bir kaynağı burada bulabilirsiniz. Biraz zaman ayırarak egzersizleri yapın.

3. Alıştırma: Çok Boyutlu Diziler

Aşağıdaki programa katılmayı düşünebilirsiniz: 

const int kStudents = 25;
const int kProblemSets = 10;

// This function returns the highest grade in the Problem Set array.
int get_high_grade(int *a, int cols, int row, int col) {
  int i, j;
  int highgrade = *a;

  for (i = 0; i < row; i++)
    for (j = 0; j < col; j++)
      if (*(a + i * cols + j) > highgrade)  // How does this line work?
        highgrade = *(a + i*cols + j);
  return highgrade;
}

int main() {
 int grades[kStudents][kProblemSets] = {
   {75, 70, 85, 72, 84},
   {85, 92, 93, 96, 86},
   {95, 90, 83, 76, 97},
   {65, 62, 73, 84, 73}
 };
 int std_num = 4;
 int ps_num = 5;
 int highest;

 highest = get_high_grade((int *)grades, kProblemSets, std_num, ps_num);
 cout << "The highest problem set score in the class is " << highest << endl;

 return 0;
}

Programda "Bu hat nasıl çalışır?" şeklinde bir satır var. - anlayabiliyor musun? Açıklamamızı burada bulabilirsiniz.

3 dimlik bir diziyi başlatan ve 3. boyut değerini üç dizinin toplamıyla dolduran bir program yazın. Çözümümüz burada yer alır.

4. Alıştırma: Kapsamlı Bir OO Tasarım Örneği

Burada, başından sonuna kadar tüm süreci kapsayan ayrıntılı bir nesne odaklı tasarım örneği verilmiştir. Son kod Java programlama dilinde yazılmış olsa da ne kadar ilerlediğinize göre kodu okuyabileceksiniz.

Lütfen zaman ayırıp bu örneğin tamamını inceleyin. Süreci ve onu destekleyen tasarım araçlarını çok iyi bir şekilde açıklamış.

Birim Testi

Giriş

Test, yazılım mühendisliği sürecinin önemli bir parçasıdır. Birim testi, tek ve küçük bir kaynak kodu modülünün işlevselliğini kontrol eden özel bir test türüdür.Ünite testi her zaman mühendis tarafından ve genellikle modülün kodlandığı anda gerçekleştirilir. Composer ve Database sınıflarını test etmek için kullandığınız test sürücüleri, birim test örnekleridir.

Ünite Testleri aşağıdaki özelliklere sahiptir. Bence...

  • bir bileşeni izole halde test etme
  • deterministiktir
  • genellikle tek bir sınıfla eşleştirilir
  • veritabanları, dosyalar, ağ gibi harici kaynaklara olan bağımlılıkları önleme
  • hızlıca uygulayabilirsiniz
  • herhangi bir sırada çalıştırılabilir

Büyük yazılım mühendisliği kuruluşlarında birim testleri için destek ve tutarlılık sağlayan otomatik çerçeveler ve metodolojiler bulunur. Bu dersin ilerleyen bölümlerinde ele alacağımız bazı gelişmiş açık kaynak birim test çerçeveleri vardır. 

Birim testi kapsamında gerçekleştirilen testler aşağıda gösterilmiştir.

İdeal bir dünyada aşağıdakileri test ederiz:

  1. Modül arayüzü, bilgilerin doğru şekilde girip çıktığından emin olmak için test edilir.
  2. Yerel veri yapıları, verileri doğru şekilde depoladığından emin olmak için incelenir.
  3. Sınır koşulları, modülün işlemeyi sınırlayan veya kısıtlayan sınırlarda doğru şekilde çalıştığından emin olmak için test edilir.
  4. Her yolun ve dolayısıyla modüldeki her bir ifadenin en az bir kez yürütüldüğünden emin olmak için modül boyunca bağımsız yolları test ederiz. 
  5. Son olarak, hataların doğru bir şekilde işlenip işlenmediğini kontrol etmemiz gerekir.

Kod Kapsamı

Gerçekte, testlerimizle tam bir "kod kapsamı" elde edemeyiz. Kod kapsamı, test durumu paketinin bir yazılım sisteminin hangi parçalarını yürüttüğünü (kapsadığını) ve hangi parçaların çalıştırılmadığını belirleyen bir analiz yöntemidir. %100 kapsama ulaşmaya çalışırsak asıl kodu yazmak yerine birim testlerini yazmaya daha fazla zaman harcarız. Aşağıdakilerin tüm bağımsız yolları için birim testleri yapmayı düşünebilirsiniz. Bu durum hızla üstel bir soruna dönüşebilir.

Bu şemada kırmızı çizgiler test edilmezken renkli olmayan çizgiler test edilir.

%100 kapsamı denemek yerine modülün düzgün çalıştığına dair güvenimizi artıran testlere odaklanıyoruz. Şu tür durumları test ederiz:

  • Boş durumlar
  • Aralık testleri, ör. pozitif/negatif değer testleri
  • Sıra dışı durumlar
  • Başarısız vakalar
  • Çoğunlukla yürütülmesi en olası yolları test etme

Ünite Testi Çerçeveleri

Çoğu birim testi çerçevesi, bir yolun yürütülmesi sırasında değerleri test etmek için onayları kullanır. Onaylar, bir koşulun doğru olup olmadığını kontrol eden ifadelerdir. Onaylama işleminin sonucu başarılı, önemli olmayan hata veya önemli hata olabilir. Bir onay gerçekleştirildikten sonra, sonuç başarılı veya önemli olmayan bir hata olursa program normal şekilde devam eder. Önemli bir hata oluşursa mevcut işlev iptal edilir.

Testler, durumu ayarlayan veya modülünüzü değiştiren bir kodla birlikte beklenen sonuçları doğrulayan bir dizi onaylamadan oluşur. Testteki tüm onaylar başarılı olursa (yani "doğru" değerini döndürürse) test başarılı olur, aksi takdirde başarısız olur.

Test durumu bir veya daha fazla test içerir. Testleri, test edilen kodun yapısını yansıtan test durumları halinde gruplandırırız. Bu kursta, ünite testi çerçevemiz olarak CPPUnit'i kullanacağız. Bu çerçeveyle C++'ta birim testleri yazıp otomatik olarak çalıştırabiliyor, böylece testlerin başarısı veya başarısızlığı hakkında bir rapor oluşturuyoruz.

PBM Birimi Kurulumu

CPPUnit kodunu SourceForge'dan indirin. Uygun bir dizin bulun ve tar.gz dosyasını buraya yerleştirin. Ardından, uygun cppunit dosya adını girerek aşağıdaki komutları (Linux, Unix'de) girin:

gunzip filename.tar.gz
tar -xvf filename.tar

Windows'da çalışıyorsanız tar.gz dosyalarını çıkarmak için bir yardımcı program bulmanız gerekebilir. Bir sonraki adım kitaplıkları derlemektir. cppunit dizinine geçin. Özel talimatları içeren bir YÜKLE dosyası vardır. Genellikle şu işlemleri çalıştırmanız gerekir:

./configure
make install

Sorunlarla karşılaşırsanız YÜKLE dosyasına bakın. Kitaplıklar genellikle cppunit/src/cppunit dizininde bulunur. Derlemenin çalışıp çalışmadığını kontrol etmek için cppunit/examples/simple dizinine gidip "make" yazın. Her şey derlenirse hazırsınız demektir.

Burada mükemmel bir eğitim bulabilirsiniz. Lütfen bu eğiticiyi izleyip karmaşık sayı sınıfı ve ilişkili birim testlerini oluşturun. cppunit/examples dizininde birkaç örnek daha vardır.

Bunu Neden Yapmalıyım???

Birim testi, sektörde birkaç nedenden dolayı çok önemlidir. Bir nedeni zaten biliyorsunuz: Kod geliştirirken çalışmalarımızı kontrol etmek için bir yönteme ihtiyacımız var. Çok küçük bir program geliştirirken bile, programımızın beklenenleri yaptığından emin olmak için içgüdüsel olarak birtakım denetleyiciler veya sürücüler yazarız.

Mühendisler, uzun süren deneyimlere dayanarak bir programın ilk denemede işe yarama olasılığının çok düşük olduğunu bilir. Ünite testleri, test programlarını kendi kendine kontrol eden ve tekrarlanabilir hale getirerek bu fikir üzerine inşa edilir. Onaylar, çıktının manuel olarak denetlenmesi yerine geçer. Ayrıca, sonuçları yorumlamak kolay olduğundan (test başarılı veya başarısız olur) tekrar tekrar tekrar çalıştırılabilir. Böylece, kodunuzun değişime karşı daha dirençli olmasını sağlayan bir güvenlik ağı sağlanır.

Bunu somut bir şekilde ifade edelim: Tamamladığınız kodu CVS'ye ilk gönderdiğinizde mükemmel bir şekilde çalışır. Ayrıca, bir süre de mükemmel şekilde çalışmaya devam ediyor. Sonra bir gün başka birisi kodunuzu değiştirir. Er ya da geç kodunuz birileri tarafından kırılacaktır. Bunları kendi kendilerine fark edeceklerini mi düşünüyorsunuz? Kesinlikle hayır. Ancak birim testlerini yazarken bunları her gün otomatik olarak çalıştırabilen sistemler vardır. Bunlara sürekli entegrasyon sistemleri denir. Böylece X mühendisi kodunuzu kırdığında sistem, sorunu düzeltene kadar ona çirkin e-postalar gönderir. X mühendisi SİZ olsanız bile!

Birim testleri, yazılım geliştirmenize ve değişim karşısında o yazılımı güvende tutmanıza yardımcı olmaya ek olarak:

  • Yürütülebilir bir spesifikasyon ve kodla senkronize kalan dokümanlar oluşturur. Başka bir deyişle, modülün hangi davranışı desteklediğini öğrenmek için bir birim testi okuyabilirsiniz.
  • Gereksinimleri uygulamadan ayırmanıza yardımcı olur. Harici olarak görünür olan davranışla ilgili iddiada bulunduğunuz için, davranışı nasıl uygulayacağınızla ilgili fikirleri karıştırmak yerine bunu açıkça düşünme fırsatınız olur.
  • Denemeler yapmayı destekler. Bir modülün çalışma biçimini bozduğunuzda sizi uyaracak bir güvenlik ağınız varsa bunları deneyip tasarımlarınızı yeniden yapılandırma olasılığınız daha yüksektir.
  • Tasarımlarınızı iyileştirir. Kapsamlı birim testleri yazmak, genellikle kodunuzu daha test edilebilir hale getirmenizi gerektirir. Test edilebilir kod, genellikle test edilemeyen koddan daha modülerdir.
  • Kaliteyi yüksek tutar. Kritik bir sistemdeki küçük bir hata, bir şirketin milyonlarca dolarlık, daha da kötüsü kullanıcıların memnuniyetini veya güvenini kaybetmesine neden olabilir. Birim testlerinin sağladığı güvenlik ağı bu olasılığı azaltır. Ayrıca hataları erken tespit ederek kalite güvencesi ekiplerinin bariz hataları bildirmek yerine daha karmaşık ve zorlu hata senaryolarına vakit ayırmasını sağlarlar.

Composer veritabanı uygulaması için CPPUnit kullanarak birim testleri yazmak üzere zaman ayırın. Yardım için cppunit/examples/ dizinine bakın.

Google Nasıl Çalışır?

Giriş

Orta Çağ'da bir keşişin manastırının arşivlerindeki binlerce el yazmasına baktığını düşünün.“Aristoteles'in söylediği...”

manastır kütüphanesi

Neyse ki, el yazmaları içeriğe göre düzenleniyor ve her bir metinde yer alan bilgilerin bulunmasını kolaylaştırmak için özel sembollerle kazınmış. Böyle bir organizasyon olmasaydı, çalışma metinlerini bulmak çok zor olurdu.

Büyük koleksiyonlardan yazılı bilgileri depolama ve alma etkinliğine Bilgi Alma (IR) adı verilir. Bu faaliyetin önemi, yüzyıllar içinde özellikle kağıt ve matbaa gibi icatlarla birlikte giderek önem kazanmıştır. Eskiden yalnızca birkaç kişi doluydu. Ancak şimdi yüz milyonlarca insan, her gün bir arama motorunu kullanarak veya masaüstlerinde arama yaparken bilgi edinmek için uğraşıyor.

Bilgi Almaya Başlarken

şapkadaki kedi

Dr. Seuss, 30 yıl boyunca 46 çocuk kitabı yazdı. Kitaplarında kediler, inekler ve fillerden kim olduğu, gıcırdatılan kuşlar ve lorax anlatılıyordu. Hangi hikayede hangi yaratıkların yer aldığını hatırlıyor musunuz? Ebeveyn değilseniz yalnızca çocuklar size canlıların hangi Dr. Seuss hikayeleri grubuna ait olduğunu söyleyebilir:

(COW ve BEE) veya CROWS

Bu sorunu çözmemize yardımcı olması için bazı klasik bilgi alma modellerini uygulayacağız.

Bariz bir yaklaşım da kaba kuvvettir: 46 Dr. Seuss hikayesinin tamamını edinin ve okumaya başlayın. Her kitap için hangi kitabın COW ve BEE kelimelerini içerdiğini not edin ve aynı zamanda CROWS kelimesini içeren kitapları arayın. Bilgisayarlar bu aşamada bizden çok daha hızlıdır. Dr. Seuss kitaplarındaki tüm metinler dijital biçimde (örneğin metin dosyaları) varsa dosyalar arasında grep işlemleri yapabiliriz. Bu teknik, Dr. Seuss'un kitapları gibi küçük bir koleksiyonda işe yarar.

Bununla birlikte, daha fazlasına ihtiyacımız olan birçok durum vardır. Örneğin, şu anda internette bulunan tüm verilerin toplanması, grep'in işleyemeyeceği kadar büyüktür. Aynı zamanda yalnızca koşullarımızla eşleşen belgeleri istemiyoruz. Belgeleri alaka düzeyine göre sıralamaya alıştık.

grep'in yanı sıra başka bir yaklaşım da arama yapmadan önce bir koleksiyondaki dokümanların dizinini oluşturmaktır. IR değerindeki indeks, ders kitabının arkasındaki dizine benzer. Her Dr. Seuss hikayesindeki tüm kelimelerin (veya terimlerin) bir listesini hazırlıyoruz. Burada "bir", "ve" gibi kelimeleri ve diğer bağlantıları, edatları vb. dışarıda bırakıyoruz. Bunlara durdurma kelimeleri denir. Daha sonra bu bilgileri, terimleri bulmayı ve içerdikleri hikayeleri tanımlamayı kolaylaştıracak bir şekilde sunarız.

Olası bir temsil, üstte hikayelerin ve her satırda terimlerin listelendiği bir matristir. Bir sütundaki "1" değeri, terimin söz konusu sütunun hikayesinde göründüğünü belirtir.

kitap ve kelime tablosu

Her bir satırı veya sütunu bir bit vektör olarak görüntüleyebiliriz. Bir satırın bit vektörü, terimin hangi haberlerde bulunduğunu gösterir. Bir sütunun bit vektörü, hikayede hangi terimlerin görüneceğini belirtir.

Baştaki sorunumuza dönelim:

(COW ve BEE) veya CROWS

Bu terimlerin bit vektörlerini alırız ve önce bit düzeyinde VE, daha sonra da sonuçta bit düzeyinde VEYA gerçekleştiririz.

(100001 ve 010011) veya 000010 = 000011

Yanıt: "Bay Brown Can Moo! Bu, "tam eşleme" modeli olan Boole Alma modelini temsil etmektedir.

Matrisi, tüm Dr. Seuss hikayelerini ve hikayelere ilişkin tüm terimleri içerecek şekilde genişlettiğimizi varsayalım. Matris önemli ölçüde büyür ve önemli bir gözlem, girişlerin çoğunun 0 olur. Matris muhtemelen dizinin en iyi temsili değildir. Yalnızca 1’ini saklamanın bir yolunu bulmamız gerekiyor.

Bazı Geliştirmeler

Bu sorunu çözmek için IR modunda kullanılan yapıya ters çevrilmiş dizin adı verilir. Terimler içeren bir sözlük saklarız ve her terim için terimin geçtiği belgelerin kaydedildiği bir liste hazırlarız. Bu listeye yayın listesi adı verilir. Tek başına bağlı bir liste, aşağıda gösterildiği gibi bu yapıyı temsil etmek için iyi bir performans gösterir.

Bağlı listelere aşina değilseniz "C++'daki bağlı listeler" konusunda bir Google araması yapın; böyle bir listenin nasıl oluşturulacağını ve nasıl kullanıldığını açıklayan birçok kaynak bulabilirsiniz. Bu konuyu sonraki bir modülde daha ayrıntılı olarak ele alacağız.

Hikayenin adı yerine Belge Kimlikleri (DocIDs) kullandığımıza dikkat edin. Ayrıca, sorguların işlenmesini kolaylaştırdığı için bu DocID'leri de sıralarız.

Bir sorguyu nasıl işleriz? Asıl sorun için önce COW ilan listesini, ardından BEE ilan listesini buluruz. Daha sonra bunları "birleştiririz":

  1. Her iki listede de işaretçiler bulundurun ve iki yayın listesini aynı anda gözden geçirin.
  2. Her adımda, her iki işaretçinin işaret ettiği DocID'yi karşılaştırın.
  3. Bunlar aynıysa bu DocID'yi bir sonuç listesine ekleyin, aksi takdirde işaretçiyi daha küçük docID'yi işaret edecek şekilde ilerletin.

Ters çevrilmiş bir dizini şu şekilde oluşturabiliriz:

  1. İlgili her dokümana bir Doküman Kimliği atayın.
  2. Her belgenin alakalı terimlerini belirleyin (şifreleme).
  3. Her terim için terimi, bulunduğu doküman kimliğini ve bu belgedeki sıklığı içeren bir kayıt oluşturun. Belirli bir terim birden fazla belgede yer alıyorsa bu terim için birden fazla kayıt olabileceğini unutmayın.
  4. Kayıtları terime göre sıralayın.
  5. Bir terim için tek kayıtları işleyip birden fazla dokümanda yer alan terimlere ait birden çok kaydı birleştirerek sözlük ve yayın listesi oluşturun. Doküman kimliklerinin bağlantılı bir listesini (sıralı sırayla) oluşturun. Ayrıca her terimin bir frekansı da vardır. Bu sıklık, bir terimin tüm kayıtlarındaki sıklıkların toplamıdır.

Proje

Denemeler yapabileceğiniz uzun düz metin dokümanları bulun. Proje, yukarıda açıklanan algoritmaları kullanarak belgelerden ters bir dizin oluşturmaktır. Ayrıca, sorgu girişi için bir arayüz ve bunları işlemek için bir motor oluşturmanız gerekir. Forumda bir proje ortağı bulabilirsiniz.

Bu projeyi tamamlamak için olası bir süreç şu şekildedir:

  1. Yapmanız gereken ilk şey belgelerdeki terimleri tanımlamak için bir strateji tanımlamaktır. Aklınıza gelen tüm engellenecek kelimelerin bir listesini yapın ve dosyalardaki kelimeleri okuyan, terimleri kaydeden ve yok sayılan kelimeleri kaldıran bir işlev yazın. Bir yinelemede terimlerin listesini incelerken listenize daha fazla yok sayılan kelime eklemeniz gerekebilir.
  2. İşlevinizi test etmek için CPPUnit test senaryoları ve derlemeniz için her şeyi bir araya getirmek üzere bir makefile yazın. Özellikle iş ortaklarıyla çalışıyorsanız dosyalarınızı CVS'ye kontrol edin. CVS örneğinizi uzaktan mühendislere nasıl açacağınızı araştırabilirsiniz.
  3. Konum verilerini dahil etmek için işleme ekleme. Yani, hangi dosya ve dosyanın neresinde terim yer alıyor? Sayfa numarasını veya paragraf numarasını tanımlamak için bir hesaplama yapabilirsiniz.
  4. Bu ek işlevi test etmek için CPPUnit test durumları yazın.
  5. Ters bir dizin oluşturun ve konum verilerini her bir terimin kaydında depolayın.
  6. Daha fazla test durumu yazın.
  7. Kullanıcının sorgu girmesine olanak tanıyacak bir arayüz tasarlayın.
  8. Yukarıda açıklanan arama algoritmasını kullanarak ters çevrilmiş dizini işleyin ve konum verilerini kullanıcıya döndürün.
  9. Bu son kısım için de test senaryoları eklediğinizden emin olun.

Tüm projelerde yaptığımız gibi, proje iş ortakları bulmak ve fikirlerinizi paylaşmak için forumu ve sohbeti kullanın.

Ekstra Özellik

Birçok IR sisteminde yaygın olarak görülen bir işleme adımına saplama adı verilir. Türetmenin ardındaki ana fikir, "alma" ile ilgili bilgi arayan kullanıcıların "alma", "alındı", "alma" gibi öğeleri içeren belgelerle de ilgilenecek olmasıdır. Sistemler, kötü köklendirme nedeniyle hatalara karşı savunmasız olabilir. Bu nedenle bu biraz karmaşıktır. Örneğin, "bilgi alma" ile ilgilenen bir kullanıcı, türetme nedeniyle "Golden Retriever'lar Hakkında Bilgi" başlıklı bir doküman alabilir. Türetme için yararlı bir algoritma Porter algoritmasıdır.

Uygulama: Her Yere Git!

Panoramas.dk adresinde bu kavramların bir uygulamasını inceleyebilirsiniz.