Java Günlüğüm
Yazılım, Java, BT, azıcık felsefe, biraz mizah...
  • Udemy Eğitimleri
  • Temiz Kod
  • Tasarım Kalıpları
  • Hakkımda
  • Arşiv
RSS
25 Mayıs 2010

Java Dergisi

Akin Java dergi, Java, Java Dergisi

Ülkemizde, pek çok konuda olduğu gibi yazılım konusunda da bilgi birikimi eksikliğinin temel sebeplerinden birisi de bilgi paylaşımı konusunda sıkıntılı olmamız. BT dünyasında bilgi paylaşımını sağlayan araçlardan kitap çalışmaları zaten çok yetersiz; pek çoğu çeviri zaten. Dergiler ise ya tamamen haber içerikli, yani BTcilere diğer BTcilerin neler yaptığını anlatıyor 🙂 ya da tamamen ürün odaklı, her sayıda yeni çıkan teknolojik ürünleri tanıtıyor ya da birbirleriyle kıyaslıyor. Dolayısıyla dergilerimiz çok az bir-iki istisna haricinde reklam amaçlı…

Fuar, sempozyum, konferans gibi bir araya gelmelerimiz bile yoğunlukla yukarıda, dergiler hakkında bahsettiğim özellikleri taşıyor. Dolayısıyla yazılımcılarımız yabancı kaynaklardan öğrenmeye devam ediyorlar. Ve inanın bana yabancı kaynaktan öğrenmenin tek sıkıntısı dil değil: Teknoloji, eskilerin dediği gibi, yabancılardan, kültürü alınmadan içselleştirilebilecek birşey değil. Her teknoloji, sahip olma ve kullanma ile ilgili pek çok kültürel öğeyi taşıyor. Ve teknolojinin, beraberinde gelen kültürü algılanmadan ve uyarlanmadan, farklı bir ortama aktarılması, verimli bir şekilde kullanılması ve nihayetinde içselleştirilmesi de mümkün değil. Bunun en basit örneği cep telefonu kullanımıdır. İngilizce’de cep telefonuna verilen isimden (cell-phone) tutun da Türkiye’ye döndüğüm 2001 yılına kadar ABD’deki operatörler ile cep telefonu üreticilerinin  abonelere sağladığı teknolojik hizmetlerin, şaşırtıcı bir şekilde Türkiye’dekilerden çok geride olmasının ancak böyle bir izahı olabilir: Teknolojiye verdiğiniz anlam ve onu nasıl konumlandırdığınız. Türk toplumunun teknoloji ürünlerini anlamlandırma ve konumlandırma konusundaki davranışlarının en belirleyici unsurları ise bence tüketim ve gösteriş. Aynı şey kurumsal BT kullanımında da geçerli.


Bütün bu felsefenin Java Dergisi ile alakası ne demeyin. Java Dergisi, bir başka teknoloji dergisi değil. Java Dergisi, sağlıklı bir yazılım kültürü oluşturmayı, Java teknolojisi üzerinden yapmayı hedeflemiş, özgün ve telif yazılardan oluşan ve yazarlarının bu ülkenin kültüründen çıktığı ve BT piyasasını çok iyi tanıdığı, sıkıntılarını ve ihtiyaçlarını bildiği bir dergi. Dolayısıyla genelde yazılım özelde ise Java teknolojilerinin hem evrensel hem de ülkemizde sağlıklı kullanılmasının şartlarını da okurlarına ulaştırmayı hedefleyen bir dergi. Arkadaşımız Özcan Acar’ın gayretleriyle bir araya gelmiş yazarların katkılarıyla ilk sayısı önümüzdeki günlerde çıkacak olan dergiyle alakalı bilgilere aşağıdaki linklerden ulaşabilirsiniz:

Web adresi

http://www.javadergisi.com/

Facebook grubu

http://www.facebook.com/#!/group.php?gid=108577429183373&ref=ts

Twitter

http://twitter.com/JavaDergisi

ve

Google’daki Java Dergisi Okurları grubu

http://groups.google.com.tr/group/java-dergisi-okurlari?hl=tr

Eminim böyle bir dergi kısa sürede, öncelikle Java-severlerin daha sonra da her türden yazılımcıların ilgisini çekecektir ve herkesin katkısıyla güzel bir bilgi paylaşım ortamı oluşturacaktır.

Toplam görüntülenme sayısı: 1342

14 Bunu beğendim 🙂
Tweet
Follow me
Tweet to @kaldiroglu
08 Mayıs 2010

A Short Introduction to Software Economics

Akin Yazılım Mühendisliği

What follows is a part of my master thesis that I wrote on the conditions of the competition in IT industry in Turkey. Before delving into the details of the topic I wanted to give a short account of software economics. Most of the time people understand the internal economical analysis of a software project when the topic is considered. That’s quite reasonable but there is another aspect of software economics, which is about its macroeconomic conditions in a market and for example how those conditions affect the behavior of a software house that strives to exist in a very unstable market such as the one in Turkey. So below is a short account of software economics as an instance of a wider area of study, the economics of knowledge.

I’ll provide Turkish translation of this very shortly.

According to famous Austrian economist Carl Menger, knowledge is embodied in capital goods. (Baetjer, 1998) For example cars carry the knowledge and skills of their designers and engineers in their bodies and features. Software is an extreme case of this approach. Because software is abstract in nature and reality of software is not inherently embedded in space. (Brooks, 1986) In software it is much easier to differentiate its knowledge aspect from its physical aspect. Software is embodied intellectual capital. (Baetjer, 1998)

Software products are inherently different than most of other engineering products. First of all software products are abstract and intangible in nature as stated before.  Software is invisible. (Brooks, 1986) Software products are not manufactured in the sense of other engineering manufacturing such as cars or electrical appliances; they are developed. Most of the cost of a software product is spent for developing and later maintaining it not for manufacturing it. That means once a software product is developed it costs almost nothing to manufacture it by writing it on a CD/DVD or another media or making it downloadable over the Internet.

There are fundamental differences between the economics of physical things and the economics of information. (Evans & Thomas, 1999) (More specifically economics of software may mean two different things: Economics of a software project and economics of a software market. In this study the second one is meant by the term.) Economic goods can be categorized according to whether they are rival or non-rival and whether they are excludable or non-excludable in consumption. Rival goods are those that can be consumed by only one consumer at a time. Most of the physical, durable or nondurable, goods, apples or hammers for example are rival goods. But non-rival goods can be consumed by more than one consumer at a time. For example radio waves carrying information are non-rival in that they can be absorbed by many antennas from air at the same time. Being excludable means non-paying customers can be easily excluded from having a good such as apples and hammers again. For non-excludable goods it is very expensive or sometimes totally impossible to exclude others from having benefit from it. Conventional economic goods are both rivalrous and excludable. That means they can be traded in competitive markets and are privately provided. (Romer, Endogenous Technological Change, Oct., 1990)  But ideas and technology are different:

Conventional economic goods are rival and excludable and are privately provided. Public goods are neither rival nor excludable and cannot be privately provided. The interesting feature of technological advance is that it is alleged to have the characteristics of a public good but is privately provided by firms that do research and development. (Romer, Capital, Labor, and Productivity, 1990)

Technology and more specifically information technology is nonrival. Once a piece of software is created it can be used anywhere and any number of times because ideally it is independent of any physical object. When we think of a piece of software that must have a piece of hardware to run on, then we can realize that calling software a perfectly nonrival product is an idealization. So most of information technology products including software mush have a complementary good. But for example human capital is absolutely rivalrous because it is totally tied to human body. So goods including technological ones have different levels of nonrivalry.

Nonrivalry has two implications that are very important in terms of comprehending the nature of the economics of software: One is the fact that nonrival goods can be accumulated without bound on a per capita basis. For example the benefit of a technological innovation can go much beyond what a worker can produce in her lifetime.  The second one is that making nonrival goods absolutely private is almost impossible due to spillovers. Once a technological achievement is achieved by a firm, that firm would normally try to protect it via patents and other legal ways so that only can it get a competitive advantage out of that achievement. But that’s not easy, for example the period of time to prevent such an invention from being used by other economic agents does not last longer than that of most physical goods. So nonrival goods have incomplete excludability which is  a function of both technology and legal system. (Romer, Endogenous Technological Change, Oct., 1990)

A software product is an intellectual property of the person or institution that developes it. But it is still too hard to completely protect a piece of software’s behavior or properties or any technique or approach embodied within it from others to copy, imitate it in a variaty of ways; because software is abstract.

When a piece of software is sold while the new owner has it, the seller does not cease owning it, itcan sell the same software again and again with almost no extra cost if that software is of type packaged software. This is called zero-marginal cost of software production. But developing a new software may cost the same as the first one.

The third and most fundamental premise is that instructions for working with raw materials are inherently different from other economic goods. Once the cost of creating a new set of instructions has been incurred, the instructions can be used over and over again at no additional cost. Developing new and better instructions is equivalent to incurring a fixed cost. This property is taken to be the defining characteristic of technology. (Romer, Endogenous Technological Change, Oct., 1990)

But as explained before since the enterprise software products need a lengthly customization process for the customer the principle of zero-marginal cost does not equally  apply. This is totally due to the nature of the customized enterprise software products.

Software never decays but a software product may become unuseable. When this happens it is discarded and new and possibly better one is installed for use. Software never wears out but it frequently changes through new releases, bug fixes, etc. to keep up with new business and technological requirements.

Cost is also another topic that needs to be handled differently in the world of software because software has its own peculiarities. For example classical dichotomy of fixed cost vs. variable cost seems does not seem to be clarifying for software. Most of the cost for software is spent not for developing it but maintaining it. On the other hand different types of software have different behavior in terms of these two types of costs. While packaged software has almost zero-marginal cost customized software may have more marginal cost that its fixed cost. That’s why some software engineering costs model include different types of costs. (Wang, 2007)

Traditional and technological economical goods behave differently when one of the inputs in their production is increased. For traditional economic goods law of diminishing return holds true: In the production of those goods if one of the inputs is kept increased in amount while other inputss are fixed eventually marginal product of that input will go down.

Mechanisms of increasing returns exist alongside those of diminishing returns in all industries. But roughly speaking, diminishing returns hold sway in the traditional part of the economy—the processing industries. Increasing returns reign in the newer part—the knowledge-based industries. Modern economies have therefore become divided into two interrelated, intertwined parts—two worlds of business—corresponding to the two types of returns. (Arthur, 1996)

Information has perfectly increasing returns: spend the money to learn something once, and that knowledge can be reused at zero additional cost forever; double the number of uses and the cost per use halves. (Evans & Thomas, 1999)

Software products are believed to have increasing returns. This is mainly due to following reasons:

  • Development costs of software products are very high. Because main resources for a software products is know-how. Know-how of specific business processes and needs, know-how of software development processes, techniques and tools, and etc. Software development projects requires large amount of R&D activities. Ideally and generally once a piece of software is built it can be reused and sold again and again at a fraction of the development cost.
  • A software product attracts more and more customer once it reaches certain level of acceptance among the customers. So once a software product becomes popular even the speed of its increasing return increases. This is called network-effec or network externality. Internet triggers the network-effect and helps a lot good and bad words about a product permeate every single Internet-citizen’s mind. So the more it gains prevalence, the more likely it will emerge as a standard. (Arthur, 1996)
  • Once individuals or enterprises invest in a software product they orient themselves around that product. They get trained on that product, they change their customs accordingly, they even integrate that product into their IT infrastructure i.e. they all incorporate that product in their daily  and professional activities. After all that they follow the updates and new versions of the same product at some extra cost. So more money a customer spends on a software product more it goes into it. That’s called vendor lock-in that makes switching costs for the owner very high. Thus when a product gains a significant amount of market share its producer can set higher upgrade prices, for example. These all create effects that increase the return of a software product.

Bibliography

  • Arthur, W. B. (1996, July-Aug). Increasing Returns and the New World of Business. Harvard Business Review .
  • Baetjer, H. J. (1998). Software as Capital. IEEE Computer Society Press.
  • Brooks, F. (1986). No Silver Bullet. IEEE Computer .
  • Brynjolfsson, E. a. (Dec. 1996). Network Externalities in Microcomputer Software: An Econometric Analysis of the Spreadsheet Market. Management Science, Vol. 42, No. 12 , 1627-1647.
  • Evans, P., & Thomas, W. (1999). Blown to Bits. Harvard Business School Press.
  • Liebowitz, S. J. (Spring 1994). Network Externality: An Uncommon Tragedy. The Journal of Economic Perspectives, Vol. 8, No. 2 , 133-150.
  • Low, L. (1992). Economics of Information Technology and the Media. River Edge, NJ, USA: World Scientific Publishing Company, Incorporated.
  • McBreen, P. (2001). Software craftsmanship. Addison-Wesley Professional.
  • Romer, P. M. (1990). Capital, Labor, and Productivity. Brookings Papers on Economic Activity , Microeconomics, Vol. 1990, 337-367.
  • Romer, P. M. (Oct., 1990). Endogenous Technological Change. The Journal of Political Economy , 98 (5), 71-102.
  • Wang, Y. (2007). Software Engineering Foundations. Auerbach Pub.

Toplam görüntülenme sayısı: 1198

8 Bunu beğendim 🙂
Tweet
Follow me
Tweet to @kaldiroglu
27 Ocak 2010

Programlama Dillerinin Gelişimi – II

Akin Bilgisayar Bilimleri Algol, C, Cobol, Fortran, Java, nesne, nesne-merkezli, object, object-oriented, programlama dilleri, programlama yaklaşımları, yordam

Soyut Veri Tipleri

Programlama dillerinin, programcılarına, kendi veri yapılarını oluşturabilme yetkinliğini vermesinin ilk örneği 1975’te bir MIT profesörü olan Barbara Liskov tarafından geliştirilen CLU isimli programlama diliyle gerçekleşmiştir. Kullanıcı-tanımlı tip (user-defined type) ya da soyut veri tipi (abstract-data type) isimleri verilen bu yapılar ile kullanıcılar, dildeki integer, char gibi temel veri tiplerini kullanarak, daha karmaşık tipler oluşturabilmektedirler. Soyut veri tiplerinni en tipik örnekleri olan yığın (stack) ya da kuyruk (queue), programlarda ancak soyut veri yapılarıyla tanımlanabilirler. Modern uygulamalarda da örneğin bir müşteri kavramı ve onun adresi bu şekilde kurgulanan soyut veri tipleriyle ifade edilebilirler.

Soyut veri tipleri, sadece karmaşık verileri ifade etmekle kalmaz, aynı zamanda bu veri tipleri üzerinde uygulanabilecek operasyonları, yordamları ya da  fonksiyonları da ifade eder. Yığın soyut veri tipiyle oluşturulan bir tabak yığınına, en üste yeni bir tabak koymak, almak ya da kaç tane tabak olduğunu sormak gibi.  Çoğu zaman bu operasyonlara, soyut veri tipinin davranışları (behavior) ya da hizmetleri (services) denir. Bir soyut veri tipindeki operasyonların nasıl çalıştığı, o soyut veri tipi üzerinde çalışan müşteri kodundan (client code) bağımsızdır. Yani soyut veri tipinin operasyonlarının koduna, dışarıdan ulaşılamaz;  sadece operasyon, o tipin müşterileri tarafından çağrılabilir, soyut veri tipi üzerinde o operasyonu çağıran müşteri kodunun, operasyonun iç yapısını bilmesi mümkün ve gerekli değildir. Dolayısıyla soyut veri yapıları, tanımlarında ifade ettikleri veri yapılarını ve onlar üzerinde çalışacak operasyonları ya da o tipin dışarıya verdiği hizmetleri, bir paket içinde bir araya getirmektedir. Bu paketlemeye, kapsülleme (encapsulation) denir.

Programda ve çalışma zamanında (run-time), kapsüllenmiş bir soyut veri tipini kullanarak, o tipten üretilmiş bir değişkene  ise nesne (object ya da instance) denir. Örneğin, Müşteri, bir soyut veri tipidir ve no, isim ve soyisim gibi üç tane veri alanı vardır. Müşteri soyut veri tipinden çalışma zamanında, bilgileri (no=0, isim=Akın, soyisim=Kaldıroğlu) olan bir nesne oluşturulabilir. Benzer şekilde ayni tipten, bilgileri (no=1, isim=Salih, soyisim=Taşçı) olan bir başka nesne daha oluşturulabilir. Bu şekilde bütün müşteriler bu tipten nesneler olarak çalışma zamanında, Müşteri tipinden yaratılabilir. Dolayısıyla bütün müşteri nesnelerinin kendi no, isim ve soyisim değişkenleri ve bu değişkenlerin değerleri olacaktır.

Müşteri tipinin tanımladığı, örneğin alışVerişYap adındaki bir operasyon da bu tipten nesnelerin alış-veriş yapmalarını modeller. Bir soyut veri tipi üzerinde tanımlanan operasyonların hepsine birden, o tipin arayüzü (interface) denir. Dolayısıyla müşteri kodları (client code), bir soyut veri tipinden, o tipin arayüzünü kullanarak hizmet alır.

Aşağıda, yığın soyut veri tipi ile üzerindeki iki operasyon resmedilmiştir. Yığının, Son-Giren-İlk-Çıkar (Last-In-First-Out, LIFO) modelinde çalıştığını unutmayın.

Bu şekilde çalışan bir Yığın soyut-veri tipi geliştirdiğimizi düşünelim. Bu tipin üzerinde şöyle operasyonlar ya da davranışlar olacaktır:

  • push: Gösterimdeki put operasyonuna karşılık gelmektedir ve yığına, operasyona geçilen nesneyi ekler
  • pop:   Gösterimdeki remove operasyonuna karşılık gelmektedir ve yığından bir nesne çıkarır ki bu da en son konan nesnedir
  • pop: Gösterimdeki remove operasyonuna karşılık gelmektedir ve yığından bir nesne çıkarır ki bu da en son konan nesnedir
  • clear: Yığını temizler, içindeki bütün nesneleri siler.
  • isEmpty: Yığının boş olup olmadığına cevap verir
  • isFull: Yığının dolu olup olmadığına cevap verir
  • size: Yığında o anda kaç tane nesne olduğunu bilgisini verir
  • getCapacity: Yığındaki maximum kapasitesini görüntüler.
  • showElements: Yığındaki nesneleri, yığın formatında görüntüler.

Dolayısıyla, Yığın’ın yedi operasyondan oluşan bir arayüzü var demektir. Bir Yığın nesnesi oluşturup, kendisinden bu arayüzler yardımıyla hizmet alan yalancı (pseudo) müşteri kodu ise muhtemelen şöyle olacaktır:

Yigin yigin = new Yigin;

Apple a = new Apple;

Orange b = new Orange;

boolean isEmpty = yigin.isEmpty();

yigin.push(a);

yigin.push(b);

isEmpty = yigin.isEmpty();

int count = yigin.size();

b = (Orange) yigin.pop();

a = (Apple) yigin.pop();

count = yigin.size();

 

Yukarıdaki yalancı kodda önce bir Yığın nesnesi yaratıldı, ardından da bu nesneye 2 tane, Apple ve Orange nesneleri eklendi. Dikkat edilmesi gereken şeylerden birisi Apple ve Orange’ın da birer soyut-veri tipi olup, a ve b değişkenlerinin bu tiplerden birer nesne oldukları. Ayrıca yalancı koddaki ilk isEmpty() çağrısının false ikincisinin true döndürdüğü, ilk size() çağrısının 2 döndürürken sonrakinin 0 döndürdüğü de açıktır.

Şimdi yukarıdaki yalancı kod yerine daha gerçek kodlarla uğraşalım. Bir yığın soyut veri tipi oluşturalım ve bu tip bizim için String nesneleri tutsun. Önce yukarıda sıraladığımız davranışları arayüz olarak ifade edelim:

. . .

// Stack manipulation operations

// Push element at rear

public void push(String newElement);

// Pop element from front

public String pop();

// Remove all elements from stack

public void clear();

// Stack status operations

// Is stack empty?

public boolean isEmpty();

// Is stack full?

public boolean isFull();

// How many elements in stack?

public int size();

// Capacity of stack?

public int getCapacity();

// Outputs the elements in the stack

// For testing/debugging purposes

public void showElements();

. . .

 

Yukarıdaki kod sizi şaşırtmış olabilir? Çünkü bu kodun kendi başına birşey yapması mümkün değildir. Neden? Çünkü yukarıdaki kod, sadece hizmetleri listeliyor, bir başka deyişle hizmetlerin arayüzleri var: Yani hizmetlerin her yerden çağrılabileceğini gösteren public anahtar kelimesi, hizmetin döndürdüğü nesnenin tipi (hiçbir şey döndürmüyorsa void anahtar kelimesi), hizmetin ismi ve “(” ile “)” arasında hizmete geçilen parametrelerin listesi. Evet zaten bir davranış ya da hizmet temelde iki şeyden oluşur: Arayüzü (interface) ile gerçekleştirmesi (implementation). Arayüz yukarıdaki dört elemandan oluşur ve hizmetin “ne”liğini ifade eder. Arayüz, tip ile ondan hizmet alan müşterileri arasındaki bir anlaşmadır (agreement ya da contract) ya da protokoldur (protocol). Bir tipten üretilen nesneler, o tipin arayüzünde listelenen ve söz verilen davranışları ya da hizmetleri yerine getirirler. Gerçekleştirme ise hizmetin “nasıl”lığıdır. Yani “hizmet nasıl yerine getirilecek?” sorusunun cevabı hizmetin gerçekleştirilmesidir. Örneğin Java’da yazılan hizmetler için ki bunlara biz Java’cılar metot demeyi tercih ederiz, gerçekleştirme kısmı “{” ile “}” arasında kalan kısımdır. Bunun dışındakiler o metotun arayüzüdürler.

Bu noktada daha fazla ilerlemeden bir konuyu açıklığa kavuşturmak gerekiyor. Davranış, hizmet, arayüz, fonksiyon (function), metot (method), yordam, alt yordam (subroutine), prosedür (procedure). Yetmedi, arayüz, anlaşma ve protokol çıktı 🙂 Nedir bunlar? Hepsi aynı şeyin farklı ifadeleri mi? Şöyle açıklayayım: Pek çoğunuzun fonksiyon dediği şeye benim davranış ya da operasyon demekte ısrar etmemin sebebi :), kavramsal ile somut dünyayı ayırma isteğimdir. Sizin de farkedeceğiniz gibi, soyut veri tiplerinin yetkinliklerini, ihtiyaçlar seviyesinde konuşurken davranış ya da servis olarak ifade ederken, tasarım seviyesine inince operasyon ya da servis olarak bahsediyorum. Kodlama yani gerçekleştirme (implementation) seviyesinde ise artık programlama dili seviyesindeyiz demektir. Dolayısıyla kullandığınız dilin kültürüne göre bir kelime kullanmanız gerekiyor. Örneğin Pascal yazanlar buna prosedür ya da C++, .Net ya da Cobol programcıları aynı şeye fonksiyon derlerken Fortran’cılar hem subroutine hem fonksiyon diyebilirler. Java’cılar ise Smalltalk geleneğine uyarak, nesnelerin davranışlarına metot demeyi tercih etmektedirler. Bir tipin ya da nesnenin (dikkat edin burada da nesne ile tipi birbirlerinin yerine kullandım 🙂 ) sağladığı hizmetlerin bütününe de kavramsal seviyede arayüz denir. Anlaşma ya da protokol ise arayüz kavramının anlaşılması için kullanılan diğer yakın anlamlı kelimelerden başka birşey değildir. Tek bir davranış ya da hizmetten konuşuyorsak, yine o hizmetin arayüzünden bir önceki paragrafta sayılan dört elementin toplamı olarak bahsedebiliriz.

Peki şimdi konumuza geri dönelim. Yığın tipimizin davranışlarını ya da arayüzünü belirledik. Şimdi de bu arayüzü gerçekleştirecek kodu yazalım. Aşağıdaki böyle bir yığın tipinin Java’da, iç yapısında dizi kullanarak gerçekleştirilmiş kodudur. Tipin ismi StringStackImplementation‘dır:

public class StringStackImplementation {
	// Default maximum stack size
	private static final int MAX_STACK_SIZE = 10;

	private String[] array = new String[MAX_STACK_SIZE];
	private int pointer = MAX_STACK_SIZE - 1;

	// Stack manipulation operations
	// Push element at rear
	public void push(String newElement) {
		if (pointer >= 0) {
			array[pointer] = newElement;
			pointer--;
		}
	}

	// Pop element from front
	public String pop() {
		String element = null;
		pointer++;
		if (pointer < MAX_STACK_SIZE) {
			element = array[pointer];
			array[pointer] = null;
		}
		return element;
	}

	// Remove all elements from stack
	public void clear() {
		for (int i = 0; i < MAX_STACK_SIZE; i++) {
			array[i] = null;
		}
		pointer = MAX_STACK_SIZE - 1;
	}

	// Stack status operations
	// Is stack empty?
	public boolean isEmpty() {
		if (pointer == MAX_STACK_SIZE - 1)
			return true;
		else
			return false;
	}

	// Is stack full?
	public boolean isFull() {
		if (pointer == -1)
			return true;
		else
			return false;
	}

	// How many elements in stack?
	public int size() {
		return MAX_STACK_SIZE - pointer - 1;
	}

	// Capacity of stack?
	public int getCapacity() {
		return MAX_STACK_SIZE;
	}

	// Outputs the elements in the stack
	// For testing/debugging purposes only
	public void showElements() {
		System.out.println("\n" + size() + " elements in the stack:");
		for (int i = 0; i < MAX_STACK_SIZE; i++) {
			System.out.println(i + ": " + array[i]);
		}
	}
}

 

Bu müşteri kodu, StackTest, çalıştırıldığında çıktısı aşağıdaki gibidir:

0 elements in the stack:

0: null

1: null

2: null

3: null

4: null

5: null

6: null

7: null

8: null

9: null

1 elements in the stack:

0: null

1: null

2: null

3: null

4: null

5: null

6: null

7: null

8: null

9: Selam

2 elements in the stack:

0: null

1: null

2: null

3: null

4: null

5: null

6: null

7: null

8: abi

9: Selam

Size of stack: 2

10 elements in the stack:

0: gidiyor

1: Nasil,

2: naber?

3: senden

4: Iyilik

5: ne yok?

6: Ne var,

7: naber?

8: abi

9: Selam

gidiyor

9 elements in the stack:

0: null

1: Nasil,

2: naber?

3: senden

4: Iyilik

5: ne yok?

6: Ne var,

7: naber?

8: abi

9: Selam

Nasil,

8 elements in the stack:

0: null

1: null

2: naber?

3: senden

4: Iyilik

5: ne yok?

6: Ne var,

7: naber?

8: abi

9: Selam

0 elements in the stack:

0: null

1: null

2: null

3: null

4: null

5: null

6: null

7: null

8: null

9: null

Size of stack: 0

2 elements in the stack:

0: null

1: null

2: null

3: null

4: null

5: null

6: null

7: null

8: naber?

9: abi

Size of stack: 2

 

Böylece soyut veri yapılarıyla, karmaşık veriler ve o veriler üzerinde çalışacak fonksiyonlar bir paket olarak modellenmiş olurlar. Bu yetkinlik bizi, yordamsal dillerinin makina-merkezli dünyasından daha gerçekçi ve tabi olan bir dünyaya götürür. Çünkü gerçek dünyada çok az şey örneğin sadece bir tamsayı (integer) olarak ifade edilebilir. Demek istediğim, yaş ya da sepetteki ürün sayısı gibi yordamsal dillerde sadece tamsayı tipiyle ifade edilen bütün bu değişkenler aslında bir üst katmanda daha karmaşık bir tipin ya da nesnenin bir alt özelliğidirler. Yani aslında çalışan nesnesi yoksa onun yaşı da yoktur ya da alış-veriş sepeti (shopping cart) yoksa sepette ürün de yoktur, sayısı da yoktur, gibi. Soyut veri tipleri ise bize, yordamsal dillerin sunduğu, int, real, double ya da char gibi basit veri tiplerinden birkaçını bir araya getirerek daha karmaşık ve tabi tipler kurgulamamızı sağlarlar. Bu şekilde ben bir Müşteri tipi oluşturup, yapısını, no, isim ve soyisim gibi üç farklı değişkenle ifade edebilirim. Aksi taktirde pek çok yordamsal dilde olduğu gibi karmaşık olan Müşteri yapısını, onun int tipindeki no’suna indirgemek zorunda kalacağız.

Görüldüğü gibi soyut veri tipleri, gerçek dünyadaki olguları aslına daha uygun resmetme noktasında programcılara çok ciddi bir yetenek kazandırmaktadır. Bu yetkinlik ile programcılar, karmaşık veri yapılarıyla onlar üzerinde çalışacak davranışları, iç yapıları ya da nasıl olduğu dışarıdan görünmeyecek şekilde paket olarak modelleyebilirler. Soyut veri tiplerinin iç yapılarını dışarıdan saklayabilme yeteneğine bilgi saklama (information hiding) denir. Soyut veri tiplerinin iç yapıları, tipin değişkenlerinden oluşur ve genel olarak gerçekleştirme (implementation) olarak adlandırılır.Soyut veri tipleri, değişik dillerdeki değişik mekanizmalarla, bilgi saklama prensibini yerine getirmek üzere iç yapılarına müşteri kodundan erişimi engelleyebilirler.

Erişim kontrolü (access control) yapıları dillerde public, private gibi anahtar kelimelerle ifade edilirler. Örneğin yukarıda örneğini verdiğimiz StringStackImplementation tipinin iç yapısında yani gerçekleştirmesinde bir dizi (array) var ve bu dizi müşteri kodunda, StackTest, StringStackImplementation’dan oluşturulan “stack” isimli nesneye konan String nesnelerini tutuyor. Ama bu tipi tasarlayan ve yazan programcı, erişim kontrolü mekanizmalarını kullanarak bu dizi nesnesine erişmemize izin vermemeli. Çünkü dizi nesnesi StringStackImplementation’ın iç yapısı ve bu iç yapı dışarıdan görülmemeli. Ayrıca StringStackImplementation iki değişkene daha sahip, birisi dizi üzerindeki o anki boş odayı gösteriyor, diğeri ise zaten bir sabit, yığının maksimum kapasitesini gösteriyor. Dizi giibi bu iki değişkene de dışarıdan ulaşım mümkün değil. Sebebi ise soyutlama: Müşteri kodları, StringStackImplementation’ın dışarıya vermeyi vaad ettiği hizmetlerle ki bu hizmetler gerçekleştirme öncesinde arayüz olarak ifade edilmişlerdi, StringStackImplementation nesnelerinden hizmet almalı, bu hizmetleri alırken StringStackImplementation nesnesinin arka tarafta hangi veri yapılarını kullandığını, ne gibi algoritmalara sahip olduğunu bilmemeli. Yani müşteri kodunu yazan programcı, StringStackImplementation nesnesinin arayüzüne dayalı bir programlama (programming to interface) yapmalı, gerçekleştirilmesine dayalı bir programlama (programming to implementation) yapmamalı.

Bu şekilde, hem programlarımızda gerçekliği resmetmede daha iyi bir noktaya gelmiş oluruz hem de farklı programlar arasında bağ (coupling) azalmış olur. Bağın azalması, programların yönetilmesini ve ileride değiştirilmesini kolaylaştırır. Bir program parçası, diğer parçalardan ne ölçüde bağımsızsa, o ölçüde kolayca değiştirilebilir ve değiştirildiğinde de diğer parçalarda sıkıntılar yaşanmaz. Örneğin, yukarıdaki StringStackImplementation nesnesinin iç yapısındaki diziyi kaldırıp yerine bir bağlı-dizi (linked list) koysak, müşteri programlarının değişmesi gerekmez. Çünkü StackTest müşteri kodu, StringStackImplementation ile sadece arayüzü üzerinde haberleşiyor, StringStackImplementation’ın iç yapıları hakkında bilgi sahibi değil. Dolayısıyla bu şekilde programcılar soyutladıkları kavramları önce davranış ya da hizmetleriyle soyutlamayı, tip olarak ifade ederken paketlemeyi (encapsualtion) ve paketin içine tip için gerekli veri yapılarını koymayı, paketlerken de paketin iç yapısını saklamayı (information and implementation hiding) öğrendiler.

Soyut Veri Tipleri ve Diller

1977-1983 yılları arasında ABD Savunma Bakanlığı’nın isteği üzerine, ısmarlama olarak geliştirilen ve ismini, şair Lord Byron’un kızı, aynı zamanda da ilk programcı olarak kabul edilen Ada Lovelace’dan alan ADA dili, gelişmiş bir soyut veri yapısı desteğine sahipti.

“Daha iyi bir C” (A better C) olarak düşünülen C++ ise, Bjarne Stroustrup tarafından 1980’li yılların başında geliştirildi. Daha iyi bir C olması, C++’ın, C’nin nesne-merkezli yapılarla zenginleştirilmiş hali olmasından kaynaklanıyordu. Nitekim bu yüzden C++’ın ilk adı “C with Classes” idi. C++ da soyut veri tiplerini daha zengin mekanizmalarla destekledi.

Bu konuda nesne-merkezli programlamanın nesnesiyle soyut veri tipleri ve onların nesnelerin karıştırılmaması gereklidir. Nesne-merkezli dillerin özellikleri açıklandığında daha iyi anlaşılacağı gibi soyut veri tipleri, karmaşık tipleri yakalamada çok faydalı ve gerekli yapılar olsa bile gerçek anlamda birer nesne değildirler. Daha doğrusu, her nesne bir gerçek veri tipidir ama tersi doğru değildir. Bu durum daha iyi bir şekilde şöyle açıklanabilir: En popüler nesne-merkezli dil olan Java’da soyut veri tipi kavramı çok da fazla söz konusu değildir. Çünkü Java’nın nesne yapıları, zaten en basit haliyle soyut veri tiplerine karşılık gelmektedir. Dahası, C++, Java, C# gibi nesne-merkezli diller, soyut veri tipi kavramını daha ileri götürerek, nesne-merkezli özellikleri bünyelerine katmışlardır. Bu dilleri ise bir sonraki yazımızda ele alacağız.

Toplam görüntülenme sayısı: 1077

24 Bunu beğendim 🙂
Tweet
Follow me
Tweet to @kaldiroglu
26 Ocak 2010

Programlama Dillerinin Gelişimi – I

Akin Bilgisayar Bilimleri Algol, C, Cobol, dillerin tarihi, Fortran, Java, nesne, nesne-merkezli, object, object-oriented, programlama dillerinin tarihi, programlamanın tarihi, yazılım, yazılım dilleri

Giriş

Programlama dillerini, sadece belli söz dizimi yapılarına sahip, bilgisayara iş yaptıran soyutlamalar bütünü olarak görmek eksik bir bakış açısı olacaktır. Programlama dilleri, programlamaya belli yaklaşımları ifade ederler. Hatta tarihi gelişimlerine bakıldığında programlama dilleri, zamanının yazılım yaklaşımlarını, problem uzaylarını ve problemleri çözme tekniklerini yansıtan özelliklere sahip olmuşlardır. Her yeni programlama dili bazen devrim niteliğinde bazen de ilerleme anlamında yepyeni özellikler getirmiş, karmaşık olan yazılım geliştirme projelerinin yine karmaşık olan programlama faaliyetlerini daha basit ve üretken yapma konusunda iddalara sahip olmuşlardır.

Bu arada dillerin değişik uygulama alanlarına dolayısıyla da değişik problemlere yönelik olarak tasarlandıkları gerçeğini de gözardı etmememek gerekmektedir. Örneğin bilimsel uygulamalar, iş uygulamaları, yapay zeka, sistem geliştirme ve tamamen teknolojik bir ayrım olsa bile web, pek çok programlama dilinin kendisi için özel yapılar içerdiği alanlardandır.  Bu konuya daha ileride yine döneceğiz.

Her dili ayrı ayrı ele alıp özelliklerini incelemek bu yazının konusu olmamakla beraber belli başlı dillerden yola çıkarak 20. yüzyılın ortalarında başlayan programlama ve yazılım projesi geliştirmenin ne gibi safhalardan geçtiğini anlamakta fayda vardır.

İlk Yaklaşım: Makina ve Assembly Kodları

Programlamanın ilk yıllarında, 1950’lerde yani, programlama doğrudan makina dilinde yapılıyordu ve ortaya çıkan koda da makina kodu deniyordu. Zaten yazılan programlar da yeterince küçüktü ve üzerinde çalışılan bilgisayarlar, şu ankilerle kıyaslanamayacak derece ilkeldiler. Dolayısıyla programların etkin çalışması da önemliydi. Bu yüzden makina dili çok zaman yeterli olabiliyordu. Makina kodu, 0 ve 1’lerden oluşmakta olup, ilk nesil kod (first-generation code) olarak adlandırılmaktadır.

Daha sonraları, makina koduna çevrilebilen, 2.nesil yapılar ortaya çıktı: Assembly dilleri. Bu diller, içinde ADD, PUSH, PULL gibi kelimeler barındıran ve assembler denen çevirici programlar tarafından makina koduna çevrilebilen bir üst seviyeli dillerdi.

İlk Yüksek Seviyeli Yaklaşım: Komut-merkezli Programlama

1950’lerde makina dilinin komutlarını daha basit bir şekilde çağırmayı sağlayacak, üçüncü nesil, ilk programlama dilleri geliştirildi. Genel kabule göre ilk yüksek seviyeli dil Fortran‘dır. İsmi, “FORmula TRANslating”den türetilen ve o tarihte bir IBM çalışanı olan John Backus liderliğindeki bir takım tarafından geliştirilen bu dil, 1957 yılında ticari olarak piyasaya sürüldü. Fortran’ın en temel özelliği, matematiksel problemleri kolayca çözmeye yarayacak yapıları içermesiydi. Bu yapılar, makina dili seviyesindeki pek çok komutu daha yukarı seviyede ve daha basit şekilde yerine getiren soyut komutlardı. Bu açıdan bakıldığında programlama dilleri,  donanımdan ne kadar uzaksa, o denli soyut (abstract) yapılar içerir ve yüksek seviyeli olurlar.

Fortran bilimsel programlama amacıyla geliştirildiği için daha çok algoritmik yapıları ifade etmede yetkindi. Fortran’da verileri tutmak için değişkenler ve bu değişkenlerin tutabileceği verilerin yapılarını ifade eden tipler vardı. Fortran’ın ilk versiyonunda I, J, K, L, M, N ile başlayan değişkenler tamsayı (integer), diğerleri kayan noktalı (floating-point) verilerdi. Ayrıca, Fortran’ın ilk sürümlerinde  kıyaslama için if , döngü için de do yapıları vardı. Her ne kadar Fortran, makina diline göre daha soyut bir yapıda olsa da öngördüğü programlama yaklaşımı alt taraftaki makina dilinin çalışmasından çok da farklı değildi: Arka arkaya çalıştırılan ifadeler. İfadeler ise komutların farklı dizilişleriyle oluşuyordu. Bu şekilde bir programlama anlayışı gelişti: Komut-merkezli programlama (imperative programming).

Her programlama dilinde komutlar vardır ve komutlar bir araya gelerek ifadeleri (statement) oluştururlar. İfadeler, bir programın cümleleri gibidir. Komut-merkezli programlamada ise en önemli şey ifadelerin sırayla çalıştırılmasıdır. Bu sırayı programcı belirler ve kodunu bu şekilde yazar. Yazılan kod, bir derleyici (compiler) tarafından makina diline çevrilir ve üretilen kod da çalışma zamanında makina üzerinde çalıştırılır. Komut-merkezli programlama, en eski ve en oturmuş yaklaşımdır. Yapısı, makina diline ve yapısına çok benzediği için, genelde performansı en yüksek diller komut-merkezli dillerdir.

İlerleme: Yordamsal Programlama

Fortran’ın alt yordam (subroutine) yapısına sahip olmasına rağmen, yordamların, programlarda yoğun olarak kullanılması ve merkezi bir önem kazanması için biraz geçmesi gerekti. 1960’larda popüler olan yapısal programlama (structured programming), programı, alt parçalara bölmeyi tavsiye ediyordu. Bu yaklaşımda, akışı kontrol eden ana parça dışında, adına birim (module) denen irili ufaklı pek çok program parçası vardı.  Birimler, ana birimden ya da diğer birimlerden değer alıp onlara değer döndürebiliyorlardı. Bu birimler, kendi yerel değişkenlerine (local variables) ve yerel ifadelere sahiptiler. Bu şekilde, ayrık işler/görevler birimlerde yazılıyor ve ana birimden tekrar tekrar çağrılabiliyordu. Böylece birimsel (modular) ya da başka bir deyişle yordamsal (procedural) programlama ortaya çıktı.

Yordamlar, farklı dillerde subroutine, procedure, operation, function, method gibi adlarla anılsa da aslen karmaşıklığı, böl-parçala yöntemiyle yönetmeyi hedefleyen, tekrar kullanımı öne çıkaran ve bu şekilde hataya daha az yer veren yordamsal programlamanın en temel aracıdır. Pek çok kişi, yordamsal programlama, komut-merkezli programlama ve yapısal programlamayı aynı anlamda, birbirleri yerine kullanır çünkü bu yaklaşımlar birbirlerinin tabi devamı olarak gelişmişlerdir. Bu yüzden, komut-merkezli programlama kısmında bahsettiğimiz gibi bir programda yazılan ifadelerin ardışıl olarak çalışması, yordamsal dillerde de en temel özelliklerdendir. Bu yaklaşımın farkı, sıklıkla tekrarlanan ve ayrı görevleri ifade eden yapıların yordam ya da fonksiyonlarda saklanmasıdır. Bu konuyu biraz daha açıklayalım.

Yordamsal dillerdeki fonksiyonlar bir işi yerine getirirler ve zorunlu olmamakla birlikte, bu işi yerine getirmek için çoğu zaman girdiye ihtiyaçları olur. Fonksiyonlar, girdi üzerinde çalışıp bir çıktı üretirler. Bir yazılımdaki bir iş ihtiyacı ise, bir ya da birden fazla fonksiyonun sırayla çalışmasıyla yerine getirilir. Buna “fonksiyonel ayrışma” (functional decomposition) denir. Yani, projedeki ihtiyaç analizi (requirements analysis) safhasında ortaya çıkarılan iş ihtiyaçları daha sonra bir ya da birden fazla fonksiyonla yerine getirilecek hale dönüştürülür. Bu dönüşüme tasarım (design) denir. Tasarımda bulunan fonksiyonlar da kodlama safhasında kodlanırlar. Kodlanma sırasında programcı, fonksiyonun yerine getireceği görevi (task), ardışıl ufak adımlara böler (stepwise refinement) ve bu adımları da tek tek kodlar. Dolayısıyla yordamsal yaklaşım, önce iş ihtiyaçlarının fonksiyonel ayrışma ile fonksiyonlara dönüştürülmesi, daha sonra da her bir fonksiyonun, ufak adımlarla kodlanması prensibi üzerine çalışır. Bu sırada birden fazla fonksiyonun üzerinde çalışacağı ortak veri alanları da bulunur ve bu veriler, fonksiyonların dışındaki genel değişkenlerde (global variable) ifade edilir.

Komut-merkezli ya da yordamsal dillerin, yazılım dünyasında en erken geliştirilen ve en yaygın diller olmasının, yazılımın ilk dönemlerinde ele alınan problemlerin, bilimsel ve mühendislik problemleri olup daha çok algoritmik tabiatta olmasıyla yakından alakası vardır. İlk yüksek seviyeli dil olan Fortran ile 1958’lerin sonunda geliştirilmeye başlanan ve 1960’ların popüler dili olan Algol’un (ALGOrithmic Language) isimlendirilmesi, bu yaklaşımın tipik bir sonucudur. Öte taraftan ilk programcıların aynı zamanda birer donanımcı olup, programın üzerinde çalışacağı donanımın çalışmasından etkilendikleri de bir gerçektir. Çünkü bilgisayarların donanım yapıları da zaten ardışık emirleri CPU üzerinde yerine getirecek şekilde geliştirilmektedir. Bilgisayarların ilk çıktığı günden bu yana hakim olan mimari yaklaşım olan Van Neumann mimarisi bize zaten böyle komut tabanlı bir dünya oluşturmuştur. Yordamsal diller de ilk temsilcilerinin ortaya çıktığı 1950’li yıllardan bu yana Van Neumann yaklaşımını tekrarlamaktadırlar.

Yordamsal dünyada, ilk temsilcileri olan Fortran ve Algol’dan bu yana pek çok dil geliştirildi. COBOL (COmmon Business-Oriented Language), Fortran ve Algol’un tam aksine, tamamen iş uygulamaları (business application) geliştirmek amacıyla 1950’lerin sonunda, Algol’de olduğu gibi, bir komite tarafından tasarlandı. COBOL, dönemin diğer dilleri gibi komut-merkezli bir yapıya sahipti ve ADD VAT TO NET-PRICE gibi tamamen iş mantığı ifadelerinin kullanımına izin veriyordu. Kendinden sonra gelen diller üzerinde çok etkisi olmayan bu dil, ilk çıktığından itibaren iş uygulamalarında yaygın kullanım alanı buldu. Özellikle, 1960’lı yıllarda ABD Savunma Bakanlığı’nın (Department of Defense, DoD), projelerinde COBOL kullanımını zorunlu hale getirmesi, COBOL’un bu denli yaygın olmasının en temel sebebi olarak gösterilmektedir. Gartner Group’un 1997 yılındaki bir araştırmasına göre iş dünyasının yazılımlarının %80’ı COBOL üzerinde çalışıyordu.

Komut-merkezli diller

Öte taraftan 1960’ların sonlarında, daha sonra en yaygın işletim sistemlerinden olacak olan UNIX üzerine çalışmalar başlamıştı. UNIX’i AT&T’nin Bell Laboratuvar’larında geliştirenler, Ken Thompson, Dennis Ritchie, Brian Kernighan, bu platformda kullanmak yüksek seviyeli bir sistem diline ihtiyaç duydular. Farklı girişimler sonunda, Dennis Ritchie 1972’de C dilini geliştirdi.

C, önceleri bir sistem dili olarak görülmesine rağmen, hem sistem hem de uygulama geliştirmekte yaygın bir şekilde kullanıldı. Yordamsal bir dil olan Algol’un ileri bir sürümü olan Algol68’den ciddi bir şekilde etkilenen C ile yazılan kodlar çok rahat bir şekilde makina diline çevrilebilmektedir. C, bir sistem dili olarak ortaya çıkmasından dolayı alt seviyeli yapılara sahiptir. Örneğin C’de makina belleğini doğrudan yönetmek için yapılar mevcuttur.

Farklı kişi ve kurumlarca geliştirilen C’nin orjinal tanımı, ünlü 1978 baskılı, Beyaz Kitap, (“the White Book”), The C Programming Language’de Brian Kernighan ve Dennis M. Ritchie tarafından yapıldı. C, 1989 yılında Amerikan Ulusal Standarlar Kurumu (American National Standards Institute (ANSI)) tarafından standart hale getirildi.

C’nin yaygınlık kazanmasının en temel sebeplerinden birisi, diğer pek çok dilin C ile yazılmasıdır. Bu şekilde C, platform ile yeni dil arasında bir ara dil haline gelmiştir. Pek çok dilin derleyici ve yorumlayıcıları C ile geliştirilmektedir.

Programlama dillerinin soy ağacı (Concepts of Programming Languages 7. baskı, Sebesta, Robert W.)

Programlama dillerinin soy ağacı

(Sabesta, Robert W., Concepts of Programming Languages 7. baskı)

Yordamsal Yaklaşımın Değerlendirilmesi

Diller, karmaşık olan problem alanını (problem domain), yine karmaşık olan bilgisayar alanı (computing domain) ile çözmeye yarayan araçlardır. Diller, birbirlerinden çok farklı yapıya sahip bu iki alan arasında tercuman rolündeki aracılardır. Lakin yordamsal yaklaşımın en temel problemi, yordamsal dillerin, problem alanını modellemek yerine bilgisayar alanını modellemelerindedir. Bir başka değişle, program yazarken programcılar, problem alanını ya da daha açık bir ifadeyle, önlerine gelen bir iş ihtiyacını, yordamsal dillerin yapılarıyla ifade etmek zorundadırlar. Yordamsal diller de alttaki makina platformunu ciddi bir şekilde taklit ettiklerinden, ortaya çıkan programlar, makinaların çalışmasına çok benzer bir yapıya sahip olmaktadırlar. Eğer uygulamalarımız, matematiksel yapılarda olsaydı ve algoritmalar yardımıyla kolayca ifade edilebilselerdi, problem olmazdı. Ama her ne kadar uygulamalarımızda algoritmalar ve matematiksel ifadeler kullanılıyor da olsak, programlarda ifade ettiğimiz şeyler genelde, çok daha karmaşık ilişkilere sahip olgular. Dolayısıyla, yordamsal diller, makina ve assembly dillerine göre çok daha soyut yapılar olmalarına rağmen, programlama dünyamızı, bilgisayar yapılarıyla ifade etmemize sebep oluyorlar. Halbuki, dillerin soyutlamaları bilgisayarınkiler yerine çok daha tabi yapıları ifade etmelidir. Bu durum, konuşurken kullandığımız dillerin, hayatı resmetmekte başarılı olmak için sahip olması gereken kavramlara değil de çok daha özel bir alanın kavramlarına sahip olması halinde ortaya çıkacak zorluklardan farklı değil.  Dolayısıyla bir programlama dili, nihai olarak alttaki makinanın diline çevrilebilmeli ama bir programcıya da hayattaki bir olayı, aslına olabildiğince uygun ifade edebilme gücü de tanımalı. Yordamsal diller, bu noktada yeterince başarılı olamadıkları için eleştirilmektedirler. Çözüm nedir? Bir sonraki yazıda, muhtemel bir çözüm ele alacağım.

Toplam görüntülenme sayısı: 5237

49 Bunu beğendim 🙂
Tweet
Follow me
Tweet to @kaldiroglu
«< 68 69 70 71 72 >»

Günlüğüme Hoşgeldiniz

Bu günlükte, Yazılım Mühendisliği, Bilgi Teknolojileri, Java, kişisel gelişim ve zaman zaman da diğer konulardaki düşüncelerimi sizlerle paylaşacağım. Umarım beğenir ve hoşça vakit geçirirsiniz.

Her türlü düşüncenizi, yorum olsun, beğeni ya da eleştiri olsun, bana iletmenizi rica ediyorum sizden. Ayrıca bana akin@javaturk.org adresinden ya da Twitter'dan ulaşabilirsiniz. Videolarıma da buradan ulaşabilirsiniz.

Teşekkür ederim.

Akın Kaldıroğlu

Rahat Okumak İçin

A Decrease font size. A Reset font size. A Increase font size.

Sosyal Medya

  • Twitter
  • Facebook
  • LinkedIn
  • Youtube

Son Twitlerim

→ Takip Etmek İçin

Abone Olun

Emalinizi girerek yazılardan haberdar olun.
Loading

Son Yazılarım

  • Udemy Eğitimlerim Üzerine
  • (başlıksız)
  • Clean Code / Temiz Kod Eğitimi Udemy’de
  • Java ile Nesne-Merkezli Programlamaya Giriş Eğitimi Udemy’de
  • Selsoft Video Eğitimleri
  • Spring ile Kurumsal Yazılım Geliştirme
  • Corona Günlerinde Design Patterns
  • Corona Günlerinde Java
  • JDK 10 ve “var” Özelliği
  • Onur Özcan
  • Analist ve İş Bilgisi
  • Farklı Dillerin Bakış Açısıyla Nesne-Merkezli Programlama
  • Java Nedir?
  • Bilgi Teknolojilerinde Yetenek Yönetimi – II: Tanımlar ve Eleştiriler – I
  • Alelade Hikayeler – II: Bir Başka Performans Problemi

Popüler Yazılar ve Sayfalar

  • Java’ya Nasıl Başlarım? Java’yı Nasıl Öğrenirim? – I
  • Nasıl Yazılımcı Olalım? – II: Hangi Bölümü Okuyalım?
  • Oracle’ın Java SE Sertifikaları: OCA, OCP ve OCM
  • Java Kurulumu ve İlk Programımız
  • İş Analisti İş Tanımı
  • Java Tutorial ya da Kendi Kendine Java Öğren
  • Nasıl Yazılımcı Olalım? – I: Üniversiteli mi Alaylı mı?
  • Tasarım Kalıpları
  • Java’ya Nasıl Başlarım? Java’yı Nasıl Öğrenirim?
  • UML Nedir?

Yazı Kategorileri

Yazı Takvimi

Haziran 2025
P S Ç P C C P
 1
2345678
9101112131415
16171819202122
23242526272829
30  
« May    

Yazı Arşivi

Blogroll

  • Binnur Kurt'un Günlüğü
  • Ender'in Java Blogu
  • Erdem Seherler
  • Kızımın Günlüğü
  • Kurumsal Java
  • Levent Karagöl
  • Levent'in Java Blogu
  • Mert Can Akkan’s java tips,options, news…
  • Yaşar Safkan
  • Yasin Saygılı
  • Yazı Dünyası

Yazı Etiketleri

analiz Bilmek C Desen design pattern EJB Eğitim Fortran Hibernate Java Java'ya nasil baslarim Java dersleri Java EE Java Persistence API Java SE Java Sertifika Java Öğren Java öğreniyorum Java öğrenmek JPA Kalıp Kurumsal Java nesne nesne-merkezli No Silver Bullet object object-oriented Oracle Java Certifications pattern performans programlama programlama dilleri programlama nedir sertifika singleton tasarım tasarım deseni tasarım desenleri tasarım şablonu yazılım yazılım geliştirme Yazılım Mühendisliği yazılımın doğası yazılımın zorlukları Şablon

↑

© Java Günlüğüm 2025
Powered by WordPress • Themify WordPress Themes
 

Yorumlar Yükleniyor...