You are on page 1of 7

Software development has different levels of abstractions.

These levels range from the highest level, the real world problem, to the lowest level machine language instructions. The history of software development is actually the development of abstraction levels. Abstraction is the key to building complex software systems. There are many definitions for abstraction. One definition is concentrating on the relevant aspects of the problem and ignoring those that are not currently important. Abstraction allows problem solving at a generalization level without regards to low level details. Put another way, it allows problem solving using concepts and terms that have a familiar structure and not having to transform them into an unfamiliar structure. Since the introduction of Von Newmans stored program machine every generation has had to reinvent the practice of computer programming[1]. In the early days of computer programming programs were written using binary code. There was little distinction between data and code. Boundaries between the two were often ill defined and made distinguishing them difficult if not impossible. This required the programmer to not only be able to solve the problem at hand but also be able to program in machine code. The hardest problem was coding a program, not solving the problem. Given a problem, typically the implementation of the solution was harder than the problem itself. A thorough understanding of the machine was necessary for even the simplest problem. The barrier between understanding and solving the problem was vast. The programming language used (machine code) was so hard to use and prone to error that most of the programmer's efforts was spent understanding the language, not the problem. The language did nothing to help the programmer break through the wall of understanding.

As programs got larger and more complicated a new method to replace programming in binary was needed. Assembly language abstracted the need to understand the hardware intimately. This innovation used mnemonics which used an assembler to translate programs to machine specific instructions [2]. Instead of learning what bit accomplished what tasks, programmers instead learned mnemonics that stood for bits. For example "LDA" for "LoaD the A register" was a lot easier to remember than hex 47. Learning that PRINTIT "test" actually called a channel program that transferred a string to the printer was much easier than learning to how to program an input/output channel. Programmers were still tied to the machine, but they could spend less time learning to program, and a more time understanding the problem. This was getting closer to the problem by spending less time understanding how to implement the solution and more time on the problem at hand than the error prone details of binary coding. The advent of third-generation languages (3GLs) sought to solve the machine-specific problem and make programs more understandable to humans. Code was written using names for instructions. Translators would translate the names into machine code. These high level constructs allowed programs to be written without regards for the underlying hardware. If different hardware was used a new translator was developed for that platform. This also introduced the concept of portability. FORTRAN and COBOL each tried to mimic human language with the intent to eliminate the need for programmers. FORTRAN could be coded by scientist while COBOL could be coded by business. 3GLs allowed business to write huge complex programs that have remained in service for decades. Once again as programs grew even more in size and complexity, a new methodology was needed to make coding easier to understand and modify. The next step

was to totally hide the hardware. In a sense, the 3GLs, such as COBOL and FORTRAN, made the program hardware independent by hiding any direct reference to the machine. More time was spent solving the problem, rather than learning and remembering machine instructions. 3GLs began to be used by system vendors for operating system services. The use of 3GLs raised the abstraction levels of both the computing platform and the programming environment. Structured programming used the concept of control abstractions such as the if-then and looping statements that were incorporated into the high level languages. These control structures abstracted out certain conditions that would affect the flow of statement execution. Software was developed by defining the task that needed to be performed then breaking the tasks into smaller and smaller pieces until the language statement level was achieved (Top Down Design). The focus of top down design was the refinement of the step-by step tasks. Top Down designs takes a divide and conquer approach to software. General processing steps were broken down into smaller pieces and called in a hierarchical fashion with clear entry and exit points (modularity). Abstract data types were introduced into the programming languages to allow dealing with data in an abstract way, without taking into account the way in which the data was represented. The implementation of the data was considered to be a low level detail. The abstract data type hid the details of the specific implementation allowing programmers to deal with the data in an abstract way (encapsulation). Together modularity, self contained modules with simple interfaces between them, and Encapsulation required that the internal workings of a module be kept private. When

modifications were made to the module it would not affect other areas of the program. All of these ideas have proved their worth and remain a part of software design. The demand for developing more complex software systems in a shorter amount of time required a new approach to software design. Object oriented programming. The purpose of object oriented programming is to build a model, in code, of the objects that make up the application and the interactions between them. As with human language, its impossible to describe any process without referring to the nouns that are involved. All programming languages provide some nouns, but until the arrival object oriented languages the programmer couldnt create nouns very easily. Programming was limited to talking about the set of nouns provided by a language: numbers, characters, channels, etc. Of course, abstract structures were built around this limited set of nouns, but the code that described those abstractions was much more complex than talking about them in English [3]. Object oriented languages allow the definition of types of objects (called classes) that are derived from, or composed of, other types. In addition to this data component, the functions that belong to the data are also grouped in the class. This has at least three benefits: Encapsulation. Functions that are internal to a class can be marked as private. This means that theyre hidden from any code outside the class, so their implementation can be modified and not affect any part of the program that uses the class. The functions that are marked public form a well-defined interface that should not be changed without due consideration, because client code relies on it. Inheritance. Classes may be derived from another class, and the new class automatically contains all of the functions and data of the original class. This is useful when some

subset of the object needs an additional capability, but dont want all of the other objects to get that capability. Polymorphism. Polymorphism itself has more than one form. The first form is when a derived class overrides an inherited function with its own implementation, so that sending the same message (calling the same function) on two different objects yields a different behavior depending on their types. A second type of polymorphism is called parametric polymorphism, which means that a class provides different implementations for a function depending on the types of parameters passed to it. The desire for reusability, the encapsulation of functions and data behind a controlled interface, the logical grouping of functions around data, were some of the ideas that led to the development of object-oriented languages. Modern languages, such as C++, not only allow these abstractions, but permit the enforced implementation of restrictions on them. Because of these language features, programmers can concentrate more on what a problem is rather than how the problem will be solved. The concepts of reuse in C++ and other similar languages permit the creation of standard libraries of routines common to a problem space, and reuse these routines when convenient. Prior to modern languages, software was seen as the actual solution to a problem. Software is not the solution. Software is often the problem. The real problem in programming is understanding the problem, and trying to implement it directly in code. Early attempts (using machine and assembly language) added extreme complexity by requiring knowledge of the underlying hardware. Using current languages, however, solutions can be implemented by concentrating more on the problem. Real world entities can easily be modeled and abstracted using objects.

In modern, large-scale systems, code is usually a small piece of the overall system. Because of the large-scale problems programmers, are faced with the task of integrating the "code solution" into a larger overall system. This complicates the task, now only pieces of the solution are created, not the entire solution. Dijkstra was right. We have created more difficult problems for ourselves, because our more powerful languages permit us to solve more complex problems[4].

References 1. Brian Hayes The Post-OOP Paradigm, American Scientist (March 2003) 2. Kenneth C. Louden Programming Languages Principles and Practice, 2nd Edition, Thompson 2003 3. Coad, Peter and Edward Yourdon. Object-Oriented Analysis, 2nd Edition. Prentice Hall, 1991 4. Edsger W. Dijkstra The Humble Programmer (Turing Award Lecture), Communications of the ACM, Vol 15, No 10 (October 1972)

You might also like