Introduction - How to Use Objects: Code and Concepts (2016)

How to Use Objects: Code and Concepts (2016)

Introduction

What makes a professional developer? The short answer is obvious: A professional developer produces good-quality code, and reliably so. It is considerably less obvious how the professional developer achieves this. It is not sufficient to know all the technical details about a language and its frameworks, because this does not help in strategic decisions and does nothing for the communication within a team. It is also not sufficient to know the buzz words of design and architecture, because they give no hints as to the concrete implementation. It is not sufficient to read through catalogs of design patterns, because they focus on particular challenges and are easily misunderstood and misused if seen out of context. Instead, the professional developer has to have a firm grasp of all of these areas, and many more. He or she must see the connections and must be able to switch between the different perspectives at a moment’s notice. The code they produce, in the end, is just a reflection of a large amount of background considerations on many different details, all of which are interconnected in often subtle ways.

This book aims to cover some of the difficult terrain found along the path to professionalism that lies ahead of a developer who has just finished an introductory course on programming, a university curriculum on computer science, or a first job assignment. It presents the major topics that have proved relevant in around 30 years since the mainstream adoption of object-oriented development. Beyond that, it highlights their crucial points based on my 15 years of experience in teaching software development at all levels of a university curriculum and working through many and various software projects.

The Central Theme: Code and Concepts

The main theme of this book is that object-oriented development, and software development in general, always requires a combination of concepts and code. Without code, there will obviously be no software. Without concepts, the code will have an arbitrary, unpredictable structure. Concepts enable us to talk about the code and to keep it understandable and maintainable. They support us in making design and implementation decisions. In short, they explain why the code looks the way it does.

The field of object-oriented development offers a particularly fair amount of time-proven concepts. Here are just a few examples. At the smallest scale, the idea of replacing “method calls” with “messages” helps to keep objects independent. The approach of designing objects to take on “responsibilities” in a larger network of objects explains how even small objects can collaborate to create substantial applications. It then turns out that networks of objects often follow “patterns” such that standard problems can be solved consistently and reliably. The idea of describing method calls by “contracts” gives a consistent guide for obtaining correct code. “Frameworks” and “inversion of control” have become essential for building large applications effectively.

Concepts are useful and even necessary for writing good-quality object-oriented code, but it takes a fair amount of diligence, insight, and experience to translate them into code faithfully. Teaching experience tells us that the concepts are easily misunderstood and that subtle deviations can sometimes have disastrous consequences. In fact, the same lesson applies to many tutorials and introductory expositions. For instance, the famous MODEL-VIEW-CONTROLLER pattern is often given with a “minimal” example implementation. We have seen several cases where the model holds a reference to the concrete view class, and a single instance, too. These blunders break the entire pattern and destroy its benefits. The fact that the code works is just not good enough for professional developers.

Because code and concepts are both essential and must be linked in detail, this book always takes you all the way. For each topic, we introduce the central concepts and explain the general lay of the land with a few illustrations. But then we go on immediately to show how the concepts are rendered in concrete code. We do not stop at giving minimal examples but also explore the more intricate points. In the example of the MODEL-VIEW-CONTROLLER pattern, it is easy to get right for small examples. But as soon as models get more complex, the professional developer makes sure that only those parts that have changed are repainted. Similarly, attaching an event-listener to a button in the user interface is simple enough, but the professional must avoid freezing the display by executing long-running operations. This, in turn, requires concurrent execution.

Of course, there might still be the danger of oversights in “minimal” examples. Wherever feasible, we therefore present code taken from the Eclipse platform and highlight those elements that exhibit the concept at hand. This choice has a further advantage: It shows the concepts in action and in context. Very often, the true value of an approach, and sometimes even its justification, shows up only in really large applications. For instance, it is essential to keep software extensible. Convincing examples of extensibility can, however, be found only in modular systems such as Eclipse. Finally, if you want to dig a bit deeper into a particularly interesting point, you can jump right into the referenced sources.

In connection with the resulting code, there is one final story that is usually not told: the story of how the code actually gets written. Professional developers can become amazingly productive if they do not insist on typing their code, but know all the tricks that will make their IDE generate the code for them. For instance, knowing about the concept of “refactoring” is all right and useful. But professionals must also master the refactoring tools in Eclipse, up to the point where they recognize that three particular tools in sequence will bring about the desired code change. On the theme of code and concepts, we will therefore also highlight the Eclipse tools that apply to each concept.

The Structure of the Book

The book is organized in four parts. They approach the topic of object-oriented development by moving roughly from the “small” aspects of individual language elements to the “large” aspects of design and architecture. However, they also provide complementary answers to the same question: What does a professionally designed “object” really look like?

Part I: Language Usage Professional code always starts with professional language usage: A professional applies the language elements according to their intentions, rather than misusing them for seemingly nifty tweaks and hacks. The term “usage” is actually meant as in “usage dictionary” for natural languages; that is, if code obeys the idioms, the phrases, and the hidden connotations of the language constructs, it becomes more readable, understandable, and maintainable.

Part II: Contracts Professional code must above all be reliable. It must work in all situations that it is constructed for and it must be clear what these situations really are. The idea of design-by-contract gives a solid foundation for the necessary reasoning. It carries all the way from high-level descriptions of methods down to the details of formal software verification. As a complementary approach, the behavior of objects must be established by comprehensive testing.

Part III: Events Software of any size is usually event-driven: The application functionality is triggered by some framework that establishes the overall structure and fundamental mechanisms. At the core, the interpretation of methods changes, compared to Part II: A method does not implement a service that fulfills a specific request by the caller, but a reaction that seems most suitable to the callee. We follow this idea in the particular area of user interfaces and also emphasize the architectural considerations around the central model-view separation in that area. Because almost all applications need to do multiple things at once, we also include a brief introduction to multithreading.

Part IV: Responsibility-Driven Design One goal of object-oriented development is to keep the individual objects small and manageable. To achieve a task of any size, many objects must collaborate. The metaphor of assigning “responsibilities” to individual objects within such larger networks has proved particularly useful and is now pervasive in software engineering. After an introductory chapter on designing objects and their collaborations, we explore the ramifications of this approach in taking strategic and architectural decisions.

Together, the four parts of this book are designed to give a comprehensive view of object-oriented development: They explain the role of individual objects in the overall application structure, their reactions to incoming events, their faithful fulfillment of particular service requests, and their role in the larger context of the entire application.

How to Read the Book

The topic of object-oriented software development, as described previously, has many facets and details. What is more, the individual points are tightly interwoven to form a complex whole. Early presentations of object-oriented programming tended to point out that it takes an average developer more than a year in actual projects to obtain a sufficient overview of what this approach to programming truly entails. Clearly, this is rather unsatisfactory.

The book makes an effort to simplify reading as much as possible. The overall goal is to allow you to use the book as a reference manual. You can consult it to answer concrete questions without having to read it cover-to-cover. At the same time, the book is a proper conventional textbook: You can also follow longer and more detailed discussions through to the end. The central ingredients to this goal are the following reading aids.

Layered Presentation The presentation within each chapter, section, and subsection proceeds from the general points to the details, from crucial insights to additional remarks. As a result, you can stop reading once you feel you have a sufficient grasp on a topic and come back later for more.

Core Sections Each chapter starts with a self-contained section that explains the chapter’s core concepts. The intention is that later chapters can be understood after reading the core sections of the earlier ones. By reading the core sections of all chapters, you get a “book within a book”—that is, a high-level survey of object-oriented software development. The core sections themselves are kept to a minimum and should be read through in one go.

Snappy Summaries Every point the text explains and elaborates on is headed by a one-sentence summary, set off visually in a gray box. These snappy summaries give a quick overview of a topic and provide landing points for jumping into an ongoing discussion.

Self-Contained Essays All top-level sections, and many subsections, are written to be self-contained treatments of particular topics. After reading the core section of a chapter, you can usually jump to the points that are currently most interesting.

Goal-Oriented Presentation The book’s outline reflects particular goals in development: How to write good methods? How to use inheritance and interfaces? How to structure an application? How to use multithreading? How to work with graphical user interfaces? How to obtain flexible software? Everything else is subsumed under those goals. In particular, design patterns are presented in the context to which they contribute most. They are kept very brief, to convey the essential point quickly, but the margin always contains a reference to the original description for completeness.

Extensive Cross-Referencing Jumping into the midst of a discussion means you miss reading about some basics. However, chances are you have a pretty good idea about those anyway. To help out, all discussions link back to their prerequisites in the margin. So if you stumble upon an unknown concept, you know where to look it up. It is usually a good idea to read the core section of the referenced chapter as well. In the other direction, many of the introductory topics have forward pointers to more details that will give additional insights. In particular, the core sections point to further information about individual aspects.

The cross-referencing in the margin uses the following symbols:

Image

Reference to literature with further information or seminal definitions, ordered by relevance

Image

Reference to previous explanations, usually prerequisites

Image

Reference to later material that gives further aspects and details

Furthermore, many paragraphs are set apart from the normal presentation by the following symbols:

Image

Crucial details often overlooked by novices. When missed, they break the greater goals of the topic.

Image

An insight or connection with a concept found elsewhere. These insights establish the network of concepts that make up the area of object-oriented development.

Image

An insight about a previous topic that acquires a new and helpful meaning in light of the current discussion.

Image

An additional remark about some detail that you may or may not stumble over. For instance, a particular detail of a code snippet may need further explanation if you look very closely.

Image

A decision-making point. Software development often involves decisions. Where the normal presentation would gloss over viable alternatives, we make them explicit.

Image

A nifty application of particular tools, usually to boost productivity or to take a shortcut (without cutting corners).

Image

A (small) overview effect [259] can be created by looking at a language other than Java or by moving away from object-oriented programming altogether. Very often, the specifics of objects in Java are best appreciated in comparison.

Hints for Teaching with the Book

The book emerged from a series of lectures given by the author in the computer science curriculum at the University of Tübingen between 2005 and 2014. These lectures ranged from introductory courses on programming in Java through object-oriented programming and software engineering to software architecture. For this book, I have chosen those topics that are most likely to help students in their future careers as software developers. At the same time, I have made a point of treating the topics with the depth that is expected of university courses. Particularly intricate aspects are, however, postponed to the later sections of each chapter and can be omitted if desired.

If you are looking at the book as a textbook for a course, it may be interesting to know that the snappy summaries actually evolved from my transparencies and whiteboard notes. The style of the lectures followed the presentation in the book: After explaining the conceptual points, I reiterated them on concrete example code. The code shown in the book is either taken from the Eclipse platform or available in the online supplement.

The presentation of design patterns in this book, as explained earlier, is geared toward easy reading, a focus on the patterns’ main points, and close links to the context to which the patterns apply. An alternative presentation is, of course, a traditional one as given in [100,59,263], with a formalized structure of name, intent, motivation, structure, down to consequences and related patterns. I have chosen the comparatively informal approach here because I have found that it helped my students in explaining the purpose and the applications of patterns in oral exams and design exercises. In larger courses with written exams, I have often chosen a more formalized presentation to allow students to better predict the exam and to prepare more effectively. For these cases, each pattern in the book points to its original publication in the margin.

The layered presentation enables you pick any set of topics you feel are most appropriate for your particular situation. It may also help to know which sections have been used together in which courses.

CompSci2 This introductory programming course is mostly concerned with the syntax and behavior of Java and the basics of object-oriented programming (Section 1.3, Section 1.4, Section 1.6, Section 1.5). I have included event-based programming of user interfaces (Section 7.1) because it tends to be very motivating. Throughout, I have used the view of objects as collaborating entities taking on specific responsibilities (Section 11.1). This overarching explanation enabled the students to write small visual games at the end of the course.

Software Engineering The lecture gives a broad overview of practical software engineering so as to prepare the students for an extended project in the subsequent semester. I have therefore focused on the principles of object-oriented design (Section 11.1, Section 11.2.1, Section 11.5.1). To give the students a head start, I have covered those technical aspects that would come up in the projects—in particular, graphical user interfaces (Section 7.1), including the principle of model-view separation (Section 9.1, Section 9.2.1), the challenges of frameworks (Section 7.3), and the usability issue of long-running jobs (Section 7.10). I have also covered the fundamental design principles leading to maintainable code (Section 11.5), focusing on the Single Responsibility Principle (Section 11.2.1) for individual objects and the Liskov Substitution Principle for hierarchies (Section 3.1.1). Throughout, I have discussed prominent patterns—in particular, OBSERVER (Section 2.1), COMPOSITE (Section 2.3.1), ADAPTER (Section 2.4.1), PROXY (Section 2.4.3), LAYERS (Section 12.2.2), and PIPES-AND-FILTERS (Section 12.3.4).

Object-Oriented Programming This bachelor-level course builds on CompSci2 and conveys advanced programming skills. We have treated object-oriented design (Section 11.1, Section 11.2.1, Section 11.3.2, Section 11.3.3) and implementation (Section 1.2.1, Sections 1.31.8) in some depth. Because of their practical relevance, we have covered user interfaces, including custom-painted widgets and the MODEL-VIEW-CONTROLLER pattern (Section 7.1, Section 7.2, Section 7.5, Section 7.8, Section 9.2). Finite State Machines served as a conceptual basis for event-based programming (Chapter 10). As a firm foundation, I have included a thorough treatment of contracts and invariants, including the practically relevant concept of model fields (Section 4.1). I have found that practical examples serve well to convey these rather abstract topics (Section 4.2) and that interested students are happy to follow me into the realm of formal verification (Section 4.7.2).

Software Architecture 1 This lecture treats fundamental structuring principles for software products. Because of the varying backgrounds of students, I started with a brief survey of object-oriented design and development (Section 11.1, Section 11.3.2, Section 10.1). This was followed by the basic architectural patterns, following [59] and [218]: LAYERS, PIPES-AND-FILTERS, MODEL-VIEW-CONTROLLER, and INTERCEPTOR (Section 12.2.2, Section 9.2, Section 12.3.4, Section 12.3.2). Because of their practical relevance, I included UNDO/REDO (Section 9.5) and the overall structure of applications with graphical interfaces (Section 9.4). The course ended with an outlook on design for flexible and in particular extensible and reusable software (Section 12.2, Section 12.3, Section 12.4).

Software Architecture 2 This lecture covers concurrent programming and distributed systems. For space reasons, only the first area is included in the book (Section 7.10, Chapter 8).