In the software industry, Design Patterns are widely recognized. It is a widely held assumption that these patterns require customization. Recently, I have been wondering if the philosophy that these elements need customization is correct.
The source of this philosophy is obvious as Christopher Alexander’s book The Timeless Way of Building is a key source of inspiration for the authors. Alexander believes strongly that one factor contributing to the “lifeless character” of modern building is the use of modular components, and the lack of “fit” that results.
While there are many parallels between the process of building beautiful and functional buildings and building software, there are certainly significant differences. As an industry, we have sacrificed potential, mostly in the form of execution cycles, for modular components, higher-level languages, operating systems, etc. The construction industry has also made sacrifices of potential for the cost benefits of modular components. However, in the case of construction, the sacrifice has been of quality, execution time.
For the construction industry there is no equivalent to execution cycles; construction time is a separate concept more akin to development time. Even if there were such a concept, it is unlikely the construction industry would have it in such excess as the software industry. As long as computing power continues to advance, there will be excess capacity to fuel these tradeoffs.
Can design patterns move from the realm of patterns into reusable modules? Better yet, can they move from patterns into reusable syntax? It is already happening, albeit slowly, and with little formal recognition. Recognition is low because the efforts do not completely implement the patterns. Many patterns have complexities that syntax cannot completely capture. Syntax however can get close. How close would it need be for the pattern itself become unnecessary?
I have not spent the time to think about every pattern and how this might happen, but my guess is, yes, it is possible. Similar to the sacrifice of many custom assembler algorithm patterns, for generic looping constructs, I believe the same will happen to today’s patterns. The Iterator looks to be the first casualty, as languages like C# and Ruby build in constructs that codify the pattern into a much easier to use, if slightly more restrictive sheath (yield). Delegates also change a many of the patterns, especially Observer.
This is not totally a new development either, as languages as far back as Smalltalk, implemented language features that made Proxies trivial. In truth, every pattern has a large degree of busy work involved, and the best languages in the future will likely be those that automate these elements. Some creative features might take the place of patterns, or the most common forms of each pattern might become codified in the language syntax.
One idea is better codification of the delegation-by-composition design. This would allow a member variable to proxy for a class’s external interface. The example below shows one possible syntax for this.
public interface IAsset
{
decimal purchasePrice {get;}
}
public class OwnedPlane : Plane, IAsset
{
IAsset interface by asset;
private bool operational;
public bool Operational { get { return isOperational; }}
public void bought(Corporation buyer)
{
asset = new CoporateAsset(buyer);
}
public void bought(Person buyer)
{
buyer = new PersonalAsset(buyer);
}
}
public class PropertyTaxCaluclator
{
public decimal TaxPlane(OwnedPlane plane)
{
return plane.purchasePrice * (plane.operational ? FAATaxRate : normalTaxRate);
}
}
You could have a tool generate code like below, in place of the line in bold, but when then this code must be maintained. Even if your tools can regenerate the code, it will still be a distraction to review. (Remember in a real example you might have dozens of properties.)
private IAsset asset;
public decimal purchasePrice { get { return asset.purchasePrice; } }
If you are not planning to modify the code, you are far better off with a simple concise statement that says exactly what you mean. There likely will be resistance to codification, as it will require some sacrifices. In addition, there is likely to be at least a few bad implementations that do more harm than good. In the end, I believe codification will win out, as it is simply the most succinct, direct, complete and meaningful implementation.
In order to achieve a higher level of abstraction, you must provide your tools with information about a higher level of intent. The only caveat is that the design of systems to capture that intent is hard, and often requires a progressive process that first accumulates knowledge in documentation like Design Patterns. Later, general-purpose implementations incorporate this knowledge to cover the most common cases. Eventually, however, the lessons learned from these preliminary steps should result in language constructs that replace the most common designs.
For very complex patterns, I imagine there will be more intermediary steps, such as implementations in tools like Software Factories. The software factory concept is something I have only recently begun to understand, but it shows a lot of promise as a bridge between knowledge and final implementation. The promise is actually much bigger than that, but that is best left for another day.
The name software factory sounds awfully scary, conjuring up visions of slave driver bosses, and rote development. The name is unfortunate, because this is quite far from the truth, intent and reality of software factories. If I might, I would offer up the alternatives of Framework or Pattern Factories. Not only do these names better represent actual abilities, but they also avoid the negative connotations of “software factory”.
A software factory cannot generate a complete application. A software factory can generate a complexly working framework, and can use further recipes to generate pattern implementations. Only when actual business logic supplements the generated code is an application complete.
Recent Comments