NESNEYE-YÖNELİK PROGRAMLAMA GİRİŞ Yılmaz Kılıçaslan
Sunum Planı Programlama nedir? Karmaşıklık Nesneye-Yönelik Programlamanın İlkeleri
Programlama Nedir? Sanat? Mühendislik? Problem Çözme?
Yazılım Projesi Etkinlikleri PLANLAMA TASARIM ANALİZ KODLAMA VE TEST SCM/SQA BİRLEŞTİRME VE TEST TEST PLANI HAZIRLAMA TEST PROSEDÜR HAZIRLAMA KULLANIM HAZIRLIĞI
Yazılım Geliştirme Evreleri Analiz Tasarım Kodlama Engtegrasyon
Analiz Ne yapacağız? Gereklilikler Problem sahası
Tasarım Nasıl yapacağız? Genel / mantıksal tasarım Soyut düşün! Ayrıntılı / fiziksel tasarım Somuta dönüştür!
Kodlama Programı yazmaya bilgisayar başında başlama! Azar azar kodla – sık sık test et! İlk önce, ilk derleme hatasını düzelt!
Entegrasyon Birleştirilebilir ve sınanmış kod parçaları elde eder etmez, bunları birleştir! Her birleştirme sonrasında, mutlaka test yap!
Yazılım Karmaşıklığı "Einstein argued that there must be simplified explanations of nature, because God is not capricious or arbitrary. No such faith comforts the software engineer. Much of the complexity that he must master is arbitrary complexity.” Fred Brooks, 1986 "The complexity of software is an essential property, not an accidental one." Fred Brooks, 1995
Yazılım Karmaşıklığının Dört Öğesi Problem sahasının karmaşıklığı Yazılım geliştirme sürecini yönetme güçlüğü Yazılımın mümkün kıldığı esneklik Ayrık sistemlerin beklenmeyen davranışları
Problem sahasının karmaşıklığı Çatışan talepler Çelişen talepler Anlatılamayan talepler Değişen talepler ...
Yazılım geliştirme sürecini yönetme güçlüğü
Yazılımın mümkün kıldığı esneklik Bir yazılımcı herşeyi programlayabilir!
Ayrık sistemlerin beklenmeyen davranışları “When we say that a system is described by a continuous function, we are saying that it can contain no hidden surprises. Small changes in inputs will always cause correspondingly small changes in outputs.” Parnas (1985) “On the other hand, discrete systems by their very nature have a finite number of possible states; in large systems, there is a combinatorial explosion that makes this number very large.” Booch (1998)
İnsanı aşan karmaşıklık “The distinguishing characteristic of industrial-strength software is that it is intensely difficult, if not impossible, for the individual developer to comprehend all the subtleties of its design. Stated in blunt terms, the complexity of such systems exceeds the human intellectual capacity. Alas, this complexity we speak of seems to be an essential property of all large software systems. By essential we mean that we may master this complexity, but we can never make it go away.” Grady Booch, 1998
Yazılım Mühendislerinin Kapasitesi "The world is only sparsely populated with geniuses. There is no reason to believe that the software engineering community has an inordinately large proportion of them.” Lawrence Peters, 1981
Kontrolsüz Karmaşıklığın Sonuçları “Bir sistem ne kadar karmaşık olursa, top yekûn çökme olasılığı o kadar yüksek olur.” Shankar (1984) Yazılım Bunalımı: süresini ve/veya bütçesini aşmış, müşteri gerekliliklerini karşılamayan projeler.
NYP öncesi karmaşıklık-maliyet ilişkisi
How to program a computer to play good chess It used to be thought in the 1950's and on into the 1960's-that the trick to making a machine play well was to make the machine look further ahead into the branching network of possible sequences of play than any chess master can. 1990s chess-playing computer However, as this goal gradually became attained, the level of computer chess did not have any sudden spurt, and surpass human experts. In fact, a human expert can quite soundly and confidently trounce the best chess programs of this day. Hofstadter, 1979 Grandmaster Garry Kasparov, former World Chess Champion
Chunking and Chess skill In the 1940's, the Dutch psychologist Adriaan de Groot made studies of how chess novices and chess masters perceive a chess situation. Put in their starkest terms, his results imply that chess masters perceive the distribution of pieces in chunks.
Computer Systems When a computer program is running, it can be viewed on a number of levels. On each level, the description is given in the language of computer science, which makes all the de descriptions similar in some ways to each other-yet there are extremely important differences between the views one gets on the different levels.
Instructions and Data The words of memory contain not only data to be acted on, but also the program to act on the data.
The base sequence for the chromosome of bacteriophage OX174
Machine Language vs. Assembly Language 84, 0, 184, 142, 216, 198, 6, 158, 15, 36, 205, 32 If you were to enter these numbers into your computer's memory and run them under MS-DOS, you would see a dollar sign placed in the lower right hand corner of your screen, since that is what these numbers tell the computer to do. MOV AX, 47104 MOV DS, AX MOV [3998], 36 INT 32
A "stratified" picture of Al FIGURE 59. To create intelligent programs, one needs to build up a series of levels of hardware and software, so that one is spared the agony of seeing everything only on the lowest level. Descriptions of a single process on different levels will sound verb different from each other, only the top one being sufficiently chunked that it is comprehensible to us. [Adapted from P. H. Winston, Artificial Intelligence (Reading, Mass.: Addison-ifele'', 1977)]
PROGRAMLAMA YAKLAŞIMLARI Bir programlama dili algoritmalar ve veri yapılarından oluşur. Programlama dilleri programlamaya yaklaşım açısından 4 gruba ayrılabilir: Prosedür yönelimli diller (örn. Fortran, Pascal) Fonksiyon yönelimli diller (örn. Lisp) Nesne yönelimli diller (örn. C++, C#, Java) Mantık yönelimli diller (örn. Prolog)
PROSEDÜR YÖNELİMLİ DİLLERE ALTERNATİF OLARAK NESNE YÖNELİMLİ DİLLER Geleneksel prosedür yönelimli programlama yaklaşımında, bir program gerçekleştirilecek bir dizi işlem adımını, yani bir algoritmayı, tanımlar. Nesneye-yönelik yaklaşımda ise, bir program birbiriyle etkileşim halinde olan bir nesneler sistemini tanımlar. C++’ı tümüyle prosedürel bir dil olarak kullanabiliriz; fakat, ancak nesneye-yönelik bir yaklaşımla bu dilin bütün potansiyelini açığa çıkarabiliriz.
NESNEYE-YÖNELİK PROGRAMLAMANIN TEMEL KAVRAMLARI Nesneye-yönelik programlamanın temel kavramları, büyük programlar yazmayı kolaylaştıran soyutlama, programları değiştirmeyi ve korumayı kolaylaştıran saklama ve programları kolayca genişletilebilir kılan sınıf hiyerarşisidir. Herhangi bir programlama dilinde bu kavramları uygulayabilirsiniz; fakat, nesneye-yönelik programlama dilleri salt bu amaçla tasarlanmışlardır.
SOYUTLAMA - 1 “Soyutlama” , belirli bir bakış açısından, önemli özelliklere odaklanabilmek için ayrıntıları göz ardı etme sürecidir.
SOYUTLAMA - 2 Geleneksel olarak, bir programlama dili soyutlama yapmaya izin verdiği ölçüde yüksek-düzeyli (high-level) kabul edilir. C++ (ve diğer nesneye-yönelik programla dilleri) verilen bir işi C’den daha soyut bir tarzda tanımlama imkanı verirken, C de Birleştirici Dillerden daha soyut bir ortam sunar. Bir programın ne yaptığını Birleştirici Dillerden daha ayrıntılı tanımlamak mümkün müdür?
PROSEDÜREL SOYUTLAMA-1 İşlemlere ilişkin ayrıntıları göz ardı etmemize izin veren “prosedürel soyutlama” en yaygın soyutlama tarzıdır. Belirli bir dilde bir program yazarken programcı kendisini bu dilin sunmuş olduğu soyutlama düzeyiyle sınırlamak zorunda değildir. Birçok dil kullanıcı-tanımlı fonksiyonlar (rutinler, prosedürler) yardımıyla prosedürel soyutlama düzeyini daha yukarılara taşımaya izin verir.
PROSEDÜREL SOYUTLAMA-2 Kendi fonksiyonlarınızı yazarak, programın yaptığı bir dizi işleme bir isim vermiş olursunuz. Örneğin, iki karakter katarının aynılığını büyük-küçük harf ayrımı gözetmeksizin test eden aşağıdaki kodu, while (*s != ‘\0’) { if ((*s == *t) || ((*s >= ‘A’) && (*s <= ‘Z’) && ((*s+32) == *t)) || ((*t >= ‘A’) && (*t <= ‘Z’) && ((*t+32) == *s)) ) { s++; t++; } else break; } if (*s == ‘\0’) printf(“esit \n”); else printf(“esit degil \n”); bir fonksiyon içine yerleştirebiliriz: if ( !_stricmp(s, t) ) printf(“eşit \n”)
PROSEDÜREL DEKOMPOZİSYON Yapısal programlama yaklaşımında, ilk tasarım adımı programdan beklenen işlevselliği belirlemektir. Yanıtlanması gereken, “Bu program ne yapacak?” sorusudur. Ardından, istenileni gerçekleştirmesi için programın atması gereken temel adımlar yüksek-düzeyli “pseudo” kodlar ya da akış diyagramları yardımıyla belirlenir. Sonrasında, her temel adım daha küçük adımlara bölünerek tasarım daha rafine hale getirilir. Bu yaklaşıma, prosedürel ayrıştırma (“procedural decomposition”) denir.
PROSEDÜREL DEKOMPOZİSYON
VERİ SOYUTLAMASI-1 Bir veri tipinin nasıl yapılandığının ayrıntılarını göz ardı etmemize izin veren soyutlama tarzına “veri soyutlaması” denir. Örneğin, bilgisayardaki her tür veri ikili sayılar olarak düşünülebilir. Fakat, birçok programcı ondalık sayılarla düşünmeyi tercih ettiği için, dillerin çoğu tam ve “floating” sayıları destekler. Basic dili karakter katarı (string) tipini bir veri soyutlaması olarak destekler. Diğer yandan, C dili string soyutlamasını doğrudan desteklemez. Bu dilde stringler ardışık bellek hücrelerini işgal eden bir dizi karakter olarak tanımlanmıştır.
VERİ SOYUTLAMASI-2 Prosedürel soyutlama kapasitelerinin aksine, birçok dil yeni veri soyutlaması düzeyleri yaratmak konusunda sınırlı destek sağlarlar. C kullanıcı tanımlı veri tiplerini “structure”lar ve “typedef”ler aracılığıyla destekler. Birçok programcı “structure”ları basit bir değişkenler topluluğu olarak kullanır: struct KisiBilgisi { char isim[30]; long telefon; char adres1[30]; char adrese2[30]; }
Nesne: Prosedürel Soyutlama + Veri Soyutlaması Bir “structure”ın bildirimini kendisini kullanmamız gereken fonksiyonları belirtmeden yapabiliriz. C dili, içsel olarak birbirlerine bağlı olmalarına rağmen, prosedürel soyutlamayı ve veri soyutlamasını iki ayrı teknik olarak sunar. Bu tekniklerin birleştiği noktada nesne-tabanlı ya da nesneye-yönelik programlama yaklaşımı doğar.
SINIFLAR Nesneye-yönelik programlama, prosedürel soyutlama ve veri soyutlamasını sınıflar biçiminde birleştirir. Bir sınıfı tanımlarken, yüksek-düzeyli soyut bir yapıya ilişkin her şey belirlenir. Bu sınıfa ait bir nesneyi kullanırken, sınıf içinde bildirilmiş veri tipleri ve onlar üzerinde tanımlanmış işlemler göz ardı edilebilir.
SARMALAMA Programımızın tasarımını kendi işlem kümelerine sahip soyut veri tipleri etrafında yaparak kendimizi kodlama / gerçekleme detaylarından daha fazla arındırırız. Bu da bizi nesneye-yönelik programlamanın bir diğer avantajına, sarmalamaya, götürür.
Sarmalama = Bilgi Saklama “Sarmalama”, soyutlamayı desteklemek yada güçlendirmek için bir sınıfın iç yapısının gizlenmesidir. Bu gizleme, bir sınıfın “görünür” arayüzü ile “özel” gerçeklemesi arasında keskin bir ayrım yapmamızı gerektirir. Bir sınıfın arayüzü o sınıfın ne yapabileceğini, gerçeklemesi ise bunu nasıl yapabileceğini gösterir.
Verileri Fonksiyonlarla Gizleme Gerçek bir sarmalama, verileri fonksiyonlarla gizlemeyi gerektirir: Fonk. Erişilebilir verili nesne VERİ Fonk. Fonk. Fonk. Fonk. Fonk. Gizli verili nesne VERİc Fonk. Fonk. Fonk.
Modülerlik Modularity is the property of a system that has been decomposed into a set of cohesive and loosely coupled modules. Booch (1998) Header Dosyası – Örnek: // gplan.h #ifndef _GPLAN_H #define _GPLAN_H 1 #include "gtypes.h" #include "except.h" #include "actions.h" class GrowingPlan ... class FruitGrowingPlan ... class GrainGrowingPlan ... … #endif
SINIF HİYERARŞİSİ Nesneye-yönelik programlamanın, prosedürel programlamada bulunmayan, bir özelliği, tip hiyerarşisi tanımlayabilme yeteneğidir. Örneğin, C Dili bütün veri tiplerini birbirinden bağımsız olarak ele alırken, C++ bir sınıfın başka bir sınıfın alt-tipi olarak tanımlanmasına; sınıflar arası benzerlikleri bir ortak üst-sınıf altında toplamaya izin verir. Birkaç sınıf için ortak bir üst-sınıf tanımlama da bir tür soyutlamadır. Sınıfların ortaklaşa taşıdıkları bazı yönler üzerinde odaklanıp diğerlerini göz ardı etmeye izin verir. Bir sınıf hiyerarşisi tanımlamanın 2 pratik faydası vardır: Türetilmiş sınıf üst-sınıfın kodunu paylaşabilir; Türetilmiş sınıf üst-sınıfın arayüzünü paylaşabilir.
KOD KALITIMI Eğer yeni bir sınıf tanımlıyorsanız ve mevcut bir sınıfın işlevselliğinden yararlanmak istiyorsanız, yeni sınıfınızı mevcut sınıftan türetirsiniz. Bu durumda kalıtım mekanizmaları size mevcut kodu yeniden kullanma imkanı sağlar.
ARAYÜZ KALITIMI Bir diğer kalıtım stratejisi, türetilmiş sınıfın üst-sınıfının eleman fonksiyonlarının yalnızca isimlerini kalıtım yoluyla almasıdır. Türetilmiş sınıf bu fonksiyonlar için kendi kodunu kullanır. Arayüz kalıtımının temel faydası çok-biçimliliğe izin vermesidir.
ÖZET Yazılımın kendisi ve geliştirme süreçleri karmaşıktır. Karmaşıklığın üstesinden gelmenin en iyi yolu soyutlamadır. Sınıflar, Soyutlama Sarmalama Hiyerarşik veri yapılanması için gerekli desteği sağlarlar.
Kaynaklar Booch, G. 1998. Object-Orinted Analysis and Design. Addison-Wesley. Brooks, F. April 1987. No Silver Bullet: Essence and Accidents of Software Engineering. IEEE Computer vol. 20(4), p. 12. Brooks, F. 1995. "Chap. 17". "'No Silver Bullet' Refined" (Anniversary Edition with four new chapters ed.) Addison-Wesley. Hofstadter, D. 1979. Gödel, Escher, Bach: An Eternal Golden Braid, Basic Books. Parnas, D. july 1985. Software Aspects of Strategic Defense System Victoria, Canada: University of Victoria, Report DCS-47-IR. Peters, L. 1981. Software Design. New York, NY: Yourdon Press, p. 22. Shankar, K. 1984. Data Design: Types, Structures, and Abstractions. Handbook of Software Engineering. New York, NY: Van Nostrand Reinhold, p. 253.