|Chapter 15 - Patterns and Antipatterns|
A pattern is a repeatable, documented method that can be applied to a particular problem. There are many types of patterns; we have algorithms, which are essentially code patterns, analysis patterns, design patterns, architectural patterns, organisational patterns and process patterns.
The origin of patterns is open to debate. I would argue that patterns have evolved along with us, and evidence for this is found in every archaeological dig. The fine dividing lines we place between a dinner plate, tea plate, saucer, cup, mug and bowl have evolved over millennia and are all the application of a design pattern to a problem. You can eat your dinner off a saucer, but a plate is better. You can drink off a plate, but a cup is more useful.
The patterns of ancient history are design and process patterns. For example, if I want to hold a lot of water and carry it up from the river, I know of three designs - let's call them design patterns - which will help me to do so:
Use two bowls suspended from the ends of a piece of wood. Carve the centrepoint of the wood to sit comfortably on your shoulders.
Use a single bowl, and shape it so it sits easily on a cowl of rope on your head.
Use tanned animal skins to form a flexible water container.
They are referred to as design patterns to make them more specific than just patterns. They are solutions to the problem of bringing up water from the river. Each of these design patterns has associated process patterns.
Select a piece of seasoned wood. Mark out the shape required, and cut it with mallet and chisel. Use an adze to finish the shaping, then sandpaper it smooth. Finish the wood with oil to preserve it.
Clean the animal hide, stretch and tan. Mark out the shape using a waterskin pattern (see - they're everywhere) and sew. Cut away excess material. Apply resin to all stitching then turn inside out and attach carrying loops to the open end.
In Psychology, we have behavioural patterns, many of them used against the breakers of our laws. The laws themselves are patterns for correct behaviour, and deviation from them may result in action against you, depending on your luck. The processes by which they are applied to you are also patterns. If you do something wrong, your family and friends will stand against you. If you do something very wrong, the law of the land will stand against you. You will be judged to have committed a crime, and subjected to trial and punishment.
Thou shalt not kill. Do not speed. Stop at the red light. Don't drop lollipops on the carpet. Don't sneeze in someone's face. If you hear a siren, pull over; someone is responding to an emergency and should not be impeded. These are all behavioural patterns we are conditioned to follow.
Design patterns give us choices. If I need to get fuel into the engine of my vehicle, I can apply one of two design patterns. I can use a carburettor (carburettor pattern) to premix the fuel and air, or I can inject the fuel straight into the cylinder heads (fuel injection pattern). When vehicles are designed, many design patterns are applied to them. For example, I shall use the pattern of a family car. That means I shall carry four to five passengers and the steering wheel will be placed at the front on the correct side for the country of use. I shall have an engine at the front, luggage space at the back. My passengers will sit either in the front seats or back seat. They will gain entry through doors which open with a handle. All of the doors will lock to prevent unauthorised access. My windows will go up and down to let in air. I shall have a sunroof. I could carry on for quite some time with these design patterns, and indeed should do so.
By following patterns, we conform to a standard set of designs which have been proven to work. I use knowledge already existing in my industry to save time, and to be able to communicate my ideas better to my collaborators. When I deviate from a pattern, I must have a good reason for doing so, for it is less likely to please, less likely to be understood, and more likely to cost more to develop.
When designing a software system, the same arguments apply. I take the cherished patterns of the software community and apply them to my software. The process of design is first to decide on the type of system, then apply design patterns just as I did for my car.
When I build my car, I decide to build it on a production line. First I assemble the components I can buy in. Next I create production lines for the bespoke components. Then I put together the components and create a vehicle.
When I build my software, I decide to build it in accordance with my software development process. I buy in what I can. I set up projects for the common components. I set up projects for the bespoke components, and another project to manage integration and deployment.
Patterns are already working for us in treeviews, listviews, web pages and applications such as word processors, spreadsheets and 3D modellers. Each of these applications is a solution to a behavioural pattern in itself. If I want to present printed data, I use a word processor or desktop publisher. If I want to present data in grids and graphs, I use a spreadsheet.
The people who designed these applications applied design patterns to them. The applications communicate with the operating system and network using software based on patterns, and the operating system and network are themselves designed using patterns. The patterns were created by invention, iterated through subsequent abstractions and evolutions, and are now in the state where we would be foolish to design our systems without benefiting from the knowledge and experience they encapsulate.
You may be wrestling with an intractable problem right now which someone else has already solved. Not only have they solved it, but their work has been criticised, reworked, improved and immortalised as a pattern. You could pick it up, write it into your software, and you will have used a design pattern and saved yourself a headache.
Patterns in building architecture are closely related to our behavioural patterns. For example, if I enter a cinema or theatre, I expect to get through the door and find where I have to pay immediately on the other side. Architects use this as a design pattern. The pattern might state: In theatres, cinemas and other auditoria, the person entering the building should find where to purchase or collect tickets immediately, even in the event of there being no queue.
Thus the pattern is a solution to a problem in a given context.
Context: Auditoria. Problem: ensuring people can find the ticket booth. Solution: Put them right behind the door, and clearly visible.
Have you ever come across a door with a handle that needed to be pushed to open? If so, you probably pulled it, vented steam, and then pushed it. The reason for this is that there is a general pattern to doors. If you are meant to push it, there is a push panel. If you are meant to pull, then there is a handle.
We are conditioned to push and pull doors according to their panel/handle configuration. Those doors which open both ways, in hospitals, and bat wing saloon doors where cowboys come face to face with the man who shot their pa, have push panels on both sides, or nothing. They do not have two handles. you are not expected to pull.
So when you come across the push door with a handle, the pattern of expectation is that you pull. Annoying isn't it?
Antipatterns are not like antimatter. They do not annihilate patterns, leaving a tract of residual energy, flash of light, or world ending chain reaction.
Antipatterns are simply patterns which are the wrong way to go.
A cycle with five wheels is an antipattern. There is no point. A kettle with a twin spout might be useful for pouring two cups of tea at once, but it would make it difficult to pour only one cup. Hence, a bad design, a pattern which should not be followed. Antipatterns are bad practice; they are the mistakes we have made and learnt by.
Once we learn to speak in pattern language, we are immediately cleverer. We are speaking from a higher level of knowledge, built upon the foundation of those who tried and failed, those who tried and succeeded, and those who took the successes of others and improved them. To speak in pattern language, we must also know that those with whom we converse are also as fluent, and therefore as knowledgeable, as we are.
Patterns have names so that we might identify and discuss their use. You will see pattern names like pipe and filters, singleton, and antipattern names like bad is better. Occasionally, a pattern will have a number after it, pattern (183). This notation was originally used by Alexander to number and group his patterns. The GoF approach was different, they used the number to refer to the page number on which the pattern was presented. Hence Decorator (175) in the GoF book means the pattern decorator begins on page 175. Alexander's Greenhouse (175) is his 175th of 253 patterns.
The GoF approach has been carried forward into the POSA books. In the context of a book it is a very convenient pattern. Outside that context, it becomes a numbering antipattern.
As a brief example of Alexander's pattern language, consider a world without windows. It would mean there was nothing to look at on the train or plane. We would have dark rooms and no view.
We are naturally attracted towards light and views. Hence, one of Alexander's patterns is the window place. It is the 180th pattern in his book, and is referred to as Window Place (180). His patterns can be consdered object-oriented as they can be contained in other patterns, and also other patterns may contain them. Thus, they have a hierarchy which is more clear in the building patterns than in software patterns, but perhaps only because of our familiarity with our needs and our surroundings.
Entrance Room (130), Zen View (134), Light on two sides of every Room (159), Street Windows (164).
We crave the light and are drawn towards it. Thus, we are drawn towards places where there is light, and if the place where the light is does not allow us to linger there, it becomes antagonistic. We love window seats for the view and the light they provide. We like bay windows, and big windows with low sills and comfortable chairs where we can sit comfortably and gaze upon the view.
In every room where you spend any length of time during the day, make at least one window into a window place.
Alcoves (179), Low Sill (222), Built-In Seats (202), Natural Doors and Windows (221), Deep Reveals (223).
Does your house or place of work have a window place?
Patterns that can be applied to software systems at their highest level can be considered architectural. They are also known as software architectural styles, although it is far more common in software to mix these architectural styles than it is in building architecture. We shall begin with some familiar patterns:
The Client Server pattern separates presentation from data. Data is persisted in a database, extracted using stored procedures, then passed to a client where they are viewed and changed. This is a rather tired pattern now, having been superseded by the following two.
A Thin Client system has all data processing and persistence on one or more servers. The client is a moderately dumb terminal, capable only of limited presentational functionality.
Layers provide a logical structure for segmenting applications into layers of abstraction or responsibility. A typical example of this is creating a layer of user interfaces which call into layers of business logic, which themselves call into layers of data manipulation, and finally into a layer of data.
Tiered systems are logically divided into hardware partitions. Layers are sometimes grouped onto the tiers, and at other times have a one-to-one mapping across the tiers.
Object oriented solutions have long provided better building blocks than purely functional solutions. The world of objects is one of collaboration, data hiding, inheritance and polymorphism.
A Distributed solution relies on more than one server to process a piece of work or a transaction. It may also be used for fault tolerance or load balancing where the distributed parts take over the work of a failed or overburdened unit.
An Event Driven system responds to particular system events rather than processing events in order.
Batch systems are where huge updates are done periodically. Without batch processing, normal processing could be interrupted or put on hold for long periods of time. Batches include such things as global data replication. Batch may well contend for the honour of the oldest software pattern.
Pipes and filters is very useful for processing data. Each step in the process is a filter, and data is passed between the filters by pipes.
Publish and subscribe is a magazine type of pattern. First, information is published. Then it is posted out to its list of subscribers.
Anyone who has used IBMís Smalltalk or Microsoftís Visual C++ with MFC will know the Model View Controller pattern well, as this is how the products work. C++ uses a Document/View notation, where document is the same as model, and controller is the application. Data is held in the Model/Document, and displayed in one or more views. When data is changed in one view, all other views are updated by the application or controller. For example, if you have two views, one a grid of data, and the other a graph, then updating the data in the grid will automatically update the graph.
The idea behind the Microkernel is adaptability to changing system requirements. A minimal functional core is separate from extended functionality and customer specific parts. The microkernel also serves as a socket, into which the extensions are plugged and coordinated.
Any product in our vast range of applications which has been repeated by others is a pattern.
Spreadsheets, word processors, databases, email systems, vector drawing, bitmap drawing, software modellers, 3D modellers, html editors et cetera ad infinitum. They are all application patterns.
Analysis patterns are those discovered during domain analysis. The primary text in this field is Analysis Patterns, which discusses organisational structures and business models.
As an example, let's take the subject of resource allocation. Resource management is part of project management. It is a problem for the development manager (development people resource), test managers (test people resource, testing hardware resource), hospital ward managers (bed resource, nurse resource), hospital administrators (doctor resource, operating theatre resource) and bank managers (money). Everyone who manages, manages a resource. Utilising resources fully and avoiding resource conflicts is one aspect of management.
Fowler gives us a basic resource pattern:
Figure 15.1 Resource Allocation (from  figure 8.13)
This shows that both Proposed Action and Implemented Action have the same basis in Action. A proposed action books a resource of a specific type with a specified quantity. Then the implemented action uses that resource. Proposed and implemented actions can be linked or separate.
Returning to our Stationer's system discussed during design, a resource might be a pencil. It is proposed (ordered) and implemented (delivered). The pencil resource must then be topped up again from the Stationer's supplier.
The resource type is a pencil. The quantity is one. The resource allocation is a line on an order.
This is an example of a resource being consumed. Buying two cups of tea from a cafe could use the same model. In fact, almost any purchase or use of a resource could use this pattern. Which is why it is a pattern in the first place.
Now let's turn our attention to a non-consumable resource. This includes things like people, rooms and video projectors. The model of figure 15.1 requires expanding to include time periods. It must also allow us to book a specific resource or a general resource. As an example, I want me and Arthur Sixpence in the meeting, but I do not require video projector serial number 2283650902374. Any one will do. I also do not mind which meeting room I get as long as it can hold two people.
Figure 15.2 General and Specific Resource Allocation with time periods (from  figure 8.14)
This is not a design for a system. It is a model of just what is required to be able to book a meeting room and video projector for two people at a specific time. Of course, it is more general than this and could be applied with equal success to almost any resourcing system managing specific and general resources over time.
It is also a reasonable model of a software development department. A general resource is an analyst, a programmer or a software architect. A specific resource is Tex Tully: Software Architect, or Murray Gell-Mann: Quark Namer. Each of these resources can be booked to one project after another for specific time periods. Each person can be booked as a specific or general resource, as long as the same person is not booked as both at the same time. Should conflicts occur, then bookings for general resources can be shuffled, while specific resources are left fixed.
This is just one aspect of analysis covered in Analysis Patterns. There are many more fields and methods of interactions to discover. Once they are all uncovered and documented, perhaps we will be able to converse using a pattern language in the way people run their businesses or organise their domains.
In summary, analysis patterns are generalised templates for the interrelation and interactions of elements of a domain. Most often, that domain is a business, and the interactions will be the organisation of people and assets.
Design patterns are more numerous by far than all other styles of pattern. It was in design that the pattern movement in software was born. It came out of the object oriented movement, and the patterns first introduced were in the creation of object oriented solutions.
One of the goals of object-oriented software was reuse. The promise was that we would be able to buy, swap, integrate and evolve components to do almost anything. We're still a little short of goal on this one, but design patterns, hovering above the actual code and objects, do allow us a more manageable form of global reuse where we do not have to worry about licensing and support.
You have already come across one software design pattern in this book, discussed during modelling. Objects were introduced as entity, boundary and controller objects. Logically enough, this is the entity, boundary, control design pattern.
What kind of size are these patterns compared to other software axioms? I have used a few other words in the lexicon of software such as system, framework, application and algorithm. Letís put them together and see where our patterns fit in.
|Software products||Process||Project||Conceptual size|
Figure 15.3 the relative size of software terms
Conceptual integrity defines ease of use.
If this is so, you will be glad of a pattern or two, where their conceptual integrity is very high, having evolved over quite some time. The likelihood of you coming up with a better solution than an evolved pattern is probably zero. When you plug together these patterns, you are also able to drill into your designs by isolating certain methods as patterns, making the whole far more conceptually simple than the bag of code it would otherwise be.
During your design, you may find a gap in the patterns market. You might create your own pattern. Others may improve upon it, fine tuning it and abstracting it into other problem areas. Thus, it will become a more general and more useful pattern. By inventing your own pattern, you will name it, explain it, and be remembered forever in the unfolding history of software.
Creation then naming is a pattern in itself. When, in my tempestuous youth, I was a rock climber, I climbed a particular route up a crag which had not been climbed before. Having done so, I got to enter it in the register (a book in our local climbing shop), name it and give it a grade. It was, in the lexicon of rock climbing, a new route, and went something like this:
Climb: Treebeard the happy rabbit
First Ascent: Nigel Leeming (solo)
Grade: E1, 5b
Length: 7 metres
Location: Simonside North Face, Northumberland
Description: Between climbs 79 and 80. Step left
onto the ledge at the start of Thunder Crack and
climb the right hand side of the bulging, sandy arÍte.
Figure 15.4 The recording of a new route
Others have climbed it since, verifying its grade, location and description. They may have climbed it better than I, changed the grade and even the description when publishing it, but itís my route. Thatís the pattern we follow. Similarly, patterns in software need an author and a catalogue. What the patterns movement needs more than anything is a pattern for organising patterns.
The GoF divided their design patterns into three groups: creational, structural and behavioural. We shall look briefly at one of each. I do not intend to go into design patterns in great detail. The GoF book contains 23 patterns, which is around 12 pages per pattern. The POSA books dwell even longer on a single pattern, and it is in GoF, POSA and PLoP that I suggest you go for more information. In the meantime, here is a brief overview:
A singleton is a class which only ever has one instantiation. There are many examples of this design pattern in schedulers such as print queues or file system manipulators. If there was more than one of such objects, they would be vying for control over files and printers and each would prevent the other from working properly.
If you make your killer application a singleton, then only one instance of it will ever be loaded into memory. It will be able to load and control multiple documents, but there will only be a single instance of it controlling and displaying the documents. The singleton approach means that when a new document is opened, it is loaded by the existing application instance and loads far quicker than loading another instance of the application along with the document.
Figure 15.5 Singleton
When people began writing word processors, the text entered by the user was held as an array of 8 bit ascii characters. Then computers became a little more complex, and as well as being able to enter text, word processor users could also format it, albeit to an extent limited to italic and a few colours. This was handled largely by inserting formatting commands into the ascii stream.
As character based operating systems waned, we were faced with more control than ever with the introduction of a selection of fonts. Not only could we select our fonts, but we could select a style of underlined, bold, italic and so on. They were also proportional, scaleable fonts and the option of holding formatting codes in the ascii stream led to ever increasing size. Increasing size, in turn, meant a longer rendering time. Size ate up scarce memory, and more complex rendering ate up clock cycles.
But what could a poor programmer do? Picking through the machine code of a competitor was laborious, and possibly illegal. Hunting through the ever expanding open source word processors for a better way could take months.
Out of this confusion came two things. First was the need for documenting the best way to handle this problem without infringing copyrights, i.e. in design patterns. Second was the creation of a method of handling the ever increasing formatting options without reducing performance, namely the pattern Flyweight.
Whether the choice of the name of a boxing category is appropriate, or whether the name fits the task is as irrelevant as questioning the name of Treebeard the happy rabbit as a rock climb. It was chosen, we understand what is meant by it, and will continue to do so.
Flyweight is based on a piece of research where word processing documents were analysed for their use of formatting. What was found was that, on average, word processing documents contained no more than a few hundred differently formatted objects.
For example, since the words Figure 15.5 above, I have used nearly two thousand characters. However, I have used only†a few different characters. I have used a space, comma, full stop, new paragraph, question mark and most of the lower case letters, but only a few upper case letters.†In all, with the bold and italic characters, I have used less than 80 differently displayed characters. If I ignore kerning pairs, I can recreate the above text with a set of 80 objects, each with a render() function to draw themselves. Obviously, I call some of those objects more than others. Italic capital T gets called only once. Each render repositions the cursor ready for the next character.
Each of these objects is a flyweight.
Now the whole book contains a few more character formats, such as bold, bold italic, grey text, title bars etc. There will be a few hundred different formats in all, i.e. a few hundred text objects to render this complete document of getting on for a million characters.
I shall not explore this situation mathematically, for Iím sure you can see how I could render the entire document like this:
For each characterPointer
cursorLocation = characterPointer.render(cursorLocation);
The characterPointer is in fact a pointer to a Flyweight object. The Flyweight holds the format of the object, i.e. the font, colour and other embellishments, and a render function. To render as quickly as possible, the Flyweight object could even contain a pre-rendered bitmap. Drawing would then be a simple bit block transfer (or blit) from the object to the screen.
Flyweight is a fairly simple concept to grasp. The GoF explain the word processor scenario above in more detail.
Figure 15.6 Flyweight
Flyweight uses the factory pattern to create and maintain the collection of flyweights.
The chain of responsibility is used in help systems and error handling. The approach to both is the same. In error handling, if an error is not handled in the routine causing the error, it is passed up the calling chain until the error is handled. If no effort is made on the part of the program to handle the error, the operating system will shut the program down. That is, it will crash. Thus, the call stack is the chain of responsibility, and shirking the responsibility will result in termination.
In context sensitive help systems, a user requests help for a particular widget. If the widget has no help available, the user will be presented with help for the widget's owner, or the widget's owner's owner. If no context is found in the help system, help for the application will appear. In this example, if responsibility is not taken for context sensitive help, then general help is offered.
Each of these passes a request for action up the chain of responsibility until something is done about it. Similarly in the army, a request for action is passed up the chain of command until someone with the appropriate level of authority can choose to do something about it.
Figure 15.7 Chain of Responsibility
The Abstract Factory pattern is used when information about which class to create at run time is not known at design time. The creational call is sent to the abstract factory, which is then responsible at run time for knowing what to create.
When an application prints hard copy, it does so without knowing at design time which printers will be installed on the system. Even so, it sends out the print any way, and leaves it to the operating system to connect the call to a printer.
Figure 15.8 The Abstract Factory pattern in action
Figure 15.8 shows two abstract factories, one the printer selector, and the other the print to file selector.
This is a fairly simple example to demonstrate a single pattern. I shall now improve the design by using other patterns.
Pattern 1. I shall use a Proxy to provide a common interface out of the print selector and into the printer drivers.
Pattern 2. I shall create my proxies using a Factory. Each proxy will extend the abstract Proxy class.
Pattern 3. I shall use a Bridge to link between this operating system and another where a remote printer resides.
Pattern 4. As already mentioned, the Printer selector is a Singleton.
The proxy pattern is used to separate the concerns of the printer driver from the print request. Doing so will make my design and ultimate system cleaner as I will be coding different features of the system in different classes.
Figure 15.9 Design patterns used together
The value of designing this way is to identify the features of a system according to what has worked well for others before. By using an object oriented approach, and object oriented design patterns, the structure of my design is immediately familiar to those who speak the pattern language. Others can criticize my design immediately without having to dig into layers of UML models and code.
Where are you in the grand scheme of your business? How is it that you interact with other members of your business and customer to create your great works of software? How does the business's actions best support the creation of excellent software?
Is the way that you are structured and work the best way?
This is a question that has bothered me greatly of late. I began my working life in engineering, where software was written by engineers. I then moved into electronics, where software was written by electronics engineers. Then I moved to robotics where software was written again by electronics engineers. Then I came into the business world, where software was written by software developers, or as the business saw it, people in IT. After that, I worked in a software house where software was written by dedicated software developers, writing for business users, their customers. Now I write words which detail software to be written in a business environment. We are led by business type people, and have a huge hierarchy in which software developers (coders) are only a small part.
All of these environments and structures of reportability have been completely different. I have noted on my various travels around companies that their accounts departments are all similar, as are their HR departments, and their canteens. Why then, are software development organisations so hugely different? Is it because our industry is still in its teenage years, battered by hormone and indecision about what to be or where to go?
Organisational patterns are the platforms for discussing these differences.
Figure 15.10 The Virtual team
Figure 15.10 shows the Virtual Team pattern. The hierarchical reporting structure of an organisation is shown as like reporting to like until the specialist managers all report to a more general manager. When it comes to creating software, a virtual team is assembled from the different disciplines to work on the project.
Organisational patterns are not limited to the organisational structure, but extend well into how the structure works to create software. In doing so, organisational patterns begin to merge with process patterns.
The Code Ownership pattern recommends code is owned by a specified individual or team. By declaring this as so, the ownership forces certain constraints on the owner. They must define and support a set of interfaces into their code. They must keep it clean and version controlled. They must love it, nurture it, and support it from attack by malevolent others. Hence code ownership keeps code in a better condition than it would otherwise be. It is not a contradiction to the principle of extreme programming, where everyone own all the code, it is merely an alternative pattern that will work in a different environment.
You must mix and match organsational patterns just as you mix design patterns. You may choose to match code ownership with Rotation, by rotating code ownership around teams. This ensures knowledge is spread between development teams rather than remaining as a black box in another.
Organsational Principles and Patterns, discusses a number of organisational patterns under the umbrella of VRAPS (vision, rhythm, anticipation, partnering, simplification). Each of these five principles provides a home or hierarchy for the patterns.
The large scale process patterns of RUP, OPEN and OOSP have been discussed already in some detail. Beyond this, lower level process patterns are concerned with the best (and worst) ways of facilitating the various process steps and disciplines.
Process patterns cover how to make the process succeed, and how to communicate with customers in reviews and requirement gathering workshops. They can also help smooth the way between the steps of process.
Brainstorming is a useful way to create the beginnings of a vision. Such exciting work is followed up with workshops to further flesh out the loosely stated vision.
You may not consider these activities as patterns as they are part of everyday software development language. Yet they are patterns. They are patterns understood beyond software development, and using the term brainstorming can conjure up images in other's minds so you do not have to further explain what the brainstorming meeting is for. That's what patterns are for, and familiarity is the goal of the patterns movement.
Data Patterns discusses patterns for containing data. Anyone designing a database will have come across link tables to maintain cross references between tables of people and departments or products and suppliers. Similarly, you will know that the proficient use of indexes make stored procedures run faster, and lookups take less time. All of this best practice database design, just as best practice software design, is the subject of data patterns.
Consider the following problem: I wish to maintain a list of people in my business. To do so, I create the following data table:
Figure 15.11 People table
Later on, when my business has expanded, I add a column for Department. Now I have a problem of what to do when someone moves department. Do I overwrite the department record, or do I hold a historic record showing a record of which departments people have worked in?
There are two methods for holding the historic data. One is to create historical records in the same table, and mark the live record with a current record marker. The current record allows me to quickly extract the current information from the historical information.
Figure 15.12 The People table holding historic data
The benefit of this method is that I have not increased the complexity of my data, and can look up current and historic information from the same table. I shall refer to it as the CurrentRecord pattern.
It is a cheap and cheerful technique, fine for a small amount of data. But small amounts of data have a habit of becoming large amounts of data. If this is the case, a better pattern is to hold historic information in a History table. This allows efficient lookup and joins on the current data, but access to the full history of the People table through the larger and more awkward PeopleHistory table for the less frequent times it is needed.
Figure 15.13 People and historic data
There was a brief early sojourn into the world of code patterns, but it became eclipsed, and has continued to be, by the design patterns.
Code patterns are algorithms and language constructs. It is enough to say here that there are good ways to write code, and bad ways. The good ways are patterns, the bad ones antipatterns.
User interface patterns can be divided into two classes, one presentation patterns which portray presentational methods, and the other interaction patterns that define how the user interacts with those presentations.
You are no doubt familiar with presentation patterns. A treeview is a pattern for displaying and drilling down into hierarchical information. An expanding menu is a way of letting the user at lots of options without hogging screen space. Listviews give the user options for viewing lists as icons or text items. Menu/Detail allows lists or trees on the left to give access to detailed information on the right. Header/menu/detail is often used on internet sites. It is so common now that sites without a menu down the left look odd. This is a good example of an evolutionary pattern in that it was created, improved through successive evolutions, and is now ubiquitous.
The success of a presentational pattern is how well it matches the user's conceptual model.
These are applied to user interfaces to conform to a standard way of doing things. Cut and paste, undo and load, edit and save are common interaction patterns.
The wizard allows users to traverse through a card by card display of a complex process broken down into understandable chunks. Context sensitive menus allow users to popup a menu containing shortcuts for activities related to the one they are currently undertaking. Progress indicators allow us to see how much longer something is likely to take. Previews provide us with a view of something before we commit to it, i.e. print previews and file load previews. Hints displayed when hovering over items are expected, as is a context sensitive cursor. Often, we take these things so much for granted, that when they are absent (especially the progress indicator), using the computer becomes a painful and frustrating act.
As a whole, antipatterns are more interesting, even darkly humorous on occasion. Social antipatterns are drug abuser, criminal, vagrant, fool. Software antipatterns are vendor lock-in. spaghetti systems, design by committee and the most famous and popular antipattern of all, reinventing the wheel.
Vendor lock-in means a specific vendor has such a hold over your software systems that they can increase prices and change conditions as they please. You have no alternative, so no leverage to change them, and no way out.
Design by committee creates a product of such compromise that it is bland, unclear and largely useless.
As a Software Architect, you should recognise instantly when you come up against an antipattern. Not only that, you must be able to counter it with an impeccably reasoned and thought out response. Your reply will be the problems raised downstream of the antipattern, and an explanation of the benefits of the pattern which should be used instead.
Spaghetti systems are largely the creation of time. A system starts out with a few links between disparate systems. Gradually, the links increase one at a time until the links number the factorial of the separate systems.
Figure 15.14 Spaghetti code or spaghetti systems
Spaghetti can be found in code or in systems. The solution to the problem is creating a broker. This is similar to using a broker to buy and sell stocks and shares. You sell to the broker, the broker sells to anyone else in the world who wants to buy. Similarly when you buy from a broker, you don't care where it comes from. The broker is responsible for getting the shares.
The broker pattern is useful for maintaining a centralised set of data. Many services and systems provide data and demand data, and creating a broker to maintain the central repository (using the publish and subscribe pattern), means there is no spaghetti.
As pointed out in Will the Real Architecture Please Sit Down, Software Architecture is itself a pattern. It is the solution pattern to the antipattern Bad is Better.
This classic software antipattern has grown out of the need for fast delivery. Fast delivery requires rapid methods. Rapid methods deliver software faster, at the expense of completeness. Bugs are ironed out during use. It is better from the point of view of the business to have this hastily delivered software because business gains can be made if the software is in place quickly, and business gains are good. Thus, the software is bad. It is better to have the bad software to exploit a new market. Of course, this was not the vision of the business, they merely expected reduced functionality, not reduced quality.
Hastily delivered software forgets about reuse, system design or documentation. It becomes focused solely on fast delivery. The faster the better.
Unfortunately, fast often means worse even if that was not the intention, hence bad is better.
Software architecture is the solution to this antipattern as it takes the ideals of fast delivery, but delivers within a process, and within a system structure that provides reuse and sharing.
eXtreme Programming is also a solution to this antipattern. Both extreme programming and software architecture will work providing the environment is conducive to them working.
Sometimes delivering bad software can be better than delivering nothing at all. Some projects get stuck in the analysis phase. You can analyse a situation forever, and never get to the bottom of it. Every layer you uncover has its own set of worms to untangle. Eventually, you become stuck in detail and conflicting statements and there is no way out. This is analysis paralysis.
The solution to this problem is to extract the stable requirements, ignore all volatility, and deliver on the stable core. The core may then be used to force crystalisation of the previously insoluble problems.
Once upon a time, when Amalgam (a mixture of powdered silver and mercury) was first discovered, a new wave of dentists began filling holes in teeth with this rather poisonous mixture. The more conscientious drilled out the rotting tooth first and then pushed and padded amalgam into the hole. Others got a good blob of it and pushed it down into the decaying cavity with their thumb.
A growing lobby complained loudly about putting poisonous metals into the mouths of hapless (and paying) victims, and amalgam was blamed for anything from heart attacks to miscarriages. The lobby won. Amalgam was banned in the United States for fifty years. Now, of course, we use it all the time. We know better.
Amalgam was the solution, but was seen as the problem. Because the problem lobby won, the true solution to the problem of decaying teeth was banned.
Hero programmers are the problem. Because they exist, more and more software development moves beyond the control of software developers. Long nights, early mornings, weekends, no holidays. Youíve done it, Iíve done it. It leaves behind it a behemoth of incomprehensible code which becomes ever more difficult to update. There wasnít time for comments or design. It was typed in and fixed as fast as we could go. But we did it, by God, we did it.
But what did we do? Did it earn us large bonuses? [probably]. Did it create an extendable platform upon which excellent software could be written? [probably not]. Did it work forever without a fix [probably not], or did it need constant support and hand holding to keep going? [probably].
Relying on a hero programmer is a disease. Accountants get it in the neck at year end. Bosses get it in the neck all the time, and like to feed that frustration down, down, down, sometimes down as far as programmers. You see, programmers can go faster. All they need is a bit of pressure. Similarly artists, cooks and ovens can go a little faster. What you get is charred meat, still raw on the inside, cooks more petulant than Petula Petulant, a hurried picture that turns a queen into a frumpled old grumpwort, and yes, worse software. But you asked for it.
The hero programmer antipattern is conquered by communication, communication, more communication and a software process paid more than lip service.
Many software antipatterns are, in fact, organisational or process antipatterns. Design antipatterns are rather fewer in number than their equivalent design patterns.
As an example, the god class or blob becomes slowly responsible for the workings of most of a system. It is a result not of bad design, but of not having a design. Code gets added to the god class and it becomes ever more godly. Eventually, there are only a few other classes having minor responsibilities and everything of any significance is performed by god.
The solution to this problem is part process and part pattern. One is to use patterns, and the other is to get a better design in place.
The opposite of the god class is the proliferation of classes, also known as poltergeists. This time, there are so many intertwined classes that you can never get to the bottom of them. Every time you look, yet another class appears out of nowhere.
You can also have a mixed god class with a proliferation of classes. This time there is one central class, and hundreds of little ones doing lost of little things. A god and poltergeists are called a corncob.
You can often hide information by presenting too much of it. This is evident in any brochure advertising insurance or pensions. There is so much information that you cannot possibly decide which product is best for you without seeking help.
An excellent example of too much information in IT systems is nuisance alarms. A nuisance alarm is one which goes off for a trivial reason. Eventually, the operator becomes so unconcerned by them coming in so often, that he ignores the one particular alarm that identifies core meltdown in the nuclear reactor. This is extraordinarily important information. Incident sunlight on the side of the building passing the 20W/m2 is less so.
Antipatterns are discussed further in Antipatterns.
In the eighteenth century, a Swedish botanist and physician named Carolus Linnaeus (later Carl von Linnť), devised a hierarchical system for naming the five million species on Earth.
Each species belongs to a genus, each genus to a family, and so on through order, class, phylum (or division), and kingdom. The associations within the hierarchy reflect evolution and are deduced from similarities in form and physiology.
At the bottom of the hierarchy, each species is given a Latin name. Each tongue is then free to assign it a common name. For example, the species homo sapiens we call human in English, humain in French, menschlich in German, and as you travel around the world others such as ninjen no and manob. All of these words represent the latin species name homo sapiens.
Figure 15.15 A taxonomy of species
I am not suggesting we name our patterns in Latin. I am suggesting we need a structure to hold our patterns (our pieces of knowledge) in. I am also suggesting that Pattern.Code.Mathematical.Sort.Quicksort can be Quicksort.c, Quicksort.java, Quicksort.basic etc. It is a case of same thing, different dialects.
In the current vogue of togetherness, our pattern structure will be designed by committee, and there will be several disagreeing groups with their own flavours. We need a modern Linnaeus. Preferably a non-latin speaker please.
There are two catalogues of software patterns. One set is the POSA Patterns of Software Architecture (now four volumes) and the other is Pattern Language of Programming (PLoP), also in four volumes.
Doing Hard Time lists many patterns particular to real time systems.
The Hillside Group maintains an excellent website for pattern information.
A software developer will be plugging together his patterns along with his UML diagrams to create a piece of software, when suddenly (oh no!) heíll have to write a piece of code for himself.
An old hack leans over, smiling, dreaming of the day when it still used to be a chaotic bundle of fun and says:
'Old LeMessurier used to say to Architects: Any time you depart from established practice, make ten times the effort, ten times the investigation. Especially on a large project.' Thatís what old Booch used to say.
I remember when any old code would do. We used to just sit there and type it in as it came into our heads.