So it is no miracle that human thinking is primarily an hierarchical one. Our way to solve problems is decomposing them to smaller ones that we can solve separately. "Divide et impera", the old Romans taught us. Remember hierarchical databases, that suffered from redundancy, but still some kind of registries or filesystems follow that plan.
What is not so easy to understand is that hierarchy is not enough. We wanted to build a bridge from our building blocks, but it crashed all the time. Our father was not able to calculate weights, widths and angles, not even the mayor of our town or the president of our state. But our neighbour was, because he was a stress analyst that studied mathematics. So our efforts to solve the problem by hierarchical requests failed, but relations brought the solution. He came with his calculator, and our bridge was standing compact - until mother came in ...
It would be a poor life without relations. Relational databases took over. We try to avoid redundancy where we can, OnceAndOnlyOnce is the code smell we are behind. We change from WinWord to DocBook or DITA when we write bigger documents and want to reuse pieces of it in other articles. We make it available for relations.
So what about the Java programmer? We define fields and methods in classes. Methods encapsulate the fields. Classes encapsulate both. Interfaces abstract classes. But what encapsulates classes and interfaces? Packages? What are packages exactly? Mostly they are a quite arbitrary grouping of related classes. Good software designers access packages by interfaces only, but in practice this is hard to hold. When you print out the package dependency graph of your project, do you see a clear hierarchy?
From the view of UML, packages are deployment units. Administrators are expected to build a customized application by using different packages. Java supports this by a package being a directory in an hierarchical filesystem. Moreover Java provides package-visibility of fields, methods and classes, the so-called default-access modifier (when there is no private, protected or public keyword).
But we see that there is no good hierarchical item above classes. There is a JSR about "Superpackages" on the way, google for "Strawman Proposal for JSR 294 Superpackages". This might become part of the Java programming language, and then you can define package dependencies in separate specification files. Will it help?
Again we expect help from hierarchies. What about relations? Applications consist of both relational and hierarchical constructs.
Hierarchical:
- The "Is-A" hierarchy: classes extend other classes, interfaces can extend even several other interfaces.
- The "Has-A" hierarchy in concrete and abstract level:
- classes contain fields that are references to other classes,
- both classes and interfaces can contain inner classes and interfaces (simulate packages by that way).
Relational:
- Classes work together. They construct local variables of other types on the fly, sometimes even by dynamic class-loading when some concrete service implementation is not known at programming time. Remember platform-specific device drivers.
- Utility classes work together with all levels of hierarchies. Mostly they are static method collections which store no state to instance fields, and thus are quite robust and universal.
- Cross-cutting concerns are things like access control, logging, loading of language-specific texts, debugging etc. These concerns can appear everywhere. Imagine that you need to check access rights in every method, because you sell your application by features.
- Usage of external resources like databases, operating systems, network, printers.
- You try to optimize long-lasting work by using threads that work synchronously.
So what else do we need? Is this not enough to model the world?
The problem rises when maintenance takes over. The application is sold and starts to live. Versioning takes place. Parts of it have to be exchanged. The GUI is reworked every month. New database adapters have to be written, some databases seem to be exotic and do not fit our access interface. Bugs are reported and proof some concepts not to be the best.
The software maintenance claims up to seventy percent of the software production efforts. This is much. Shouldn't we think about a maintainable implementation of our product? But - are object-oriented language not optimized to provide maintenance? Or - have we hired bad designers and programmers?
Requirements are changing over time, even the best designers and programmers might have failed. Better lets look closer at the language fault. A project consists of thousands of classes, at least one million lines of code for an average project. The unclear package concept over it. This is much. And complexity goes further, into the deep. Nothing forced that programming statements that have to be in a certain order should be written into separate methods. A programmer changes the order and causes a bug. Nobody commented why a certain statement has to be here, someone removed it because it did not sound logically in that context - bug.
Complexity is a monster at the gate of chaos. We can't make money with chaos software. We need well-specified and repeatedly testable building blocks from which we can build the application. It comes out that we need something above classes (and packages that proved to be unclear). Besides, we need good coding conventions, design and programming principles, and regular training and communication for developers to come over the depth problems.
Assuming that components would ease our fight against complexity, we will find opinions about software components on the web.
A component ...
Catalysis
- is a coherent package of software that can be independently developed and delivered as a unit, and that defines interfaces by which it can be composed with other components to provide and use services.
- There is a very sharp distinction between the external interfaces of a component and its internal design and implementation.
UML
- has a Specification
- has an implementation
- conforms to a standard
- can be packaged
- can be deployed
There are component frameworks around for Java, the most notable are (open source):
- OSGI (Eclipse plug-ins are built on this) - interface driven, implementations are loadable and exchangeable during runtime, mostly programmed by static factories using OSGI utilities.
- Spring - XML and interface driven, concrete implementation classnames and values for fields and parameters are written in XML documents.
We see this is evolving. We have to wait a little.
Meanwhile we could think about what will be our requirements for those upcoming components. I made my list of expectations, and I am quite sure that we will need some more terms than just 'component' for that, or split that word into several others.
Now look, I want to divide my application into the following aspects:
- Architecture: when some functionality is in a certain "three-tier-architecture" layer (client/server/persistence), which might mean it runs on a different machine in the network. Classical architectural components are
- user interface logic
- business logic
- persistence logic
- Environment: when different environments require specialized behaviours, e.g. for different GUI-environments you might need the AWT-, Swing-, SWT-, or even Web-Brower component for your client. Environments include operating systems, database products, legacy applications, rendering devices (printers, screens, PDAs, ...), integrating scientific expert modules, and so on. This is more than just writing adapters.
- Separation of concerns: (1) software-technical knowledge and (2) professional business-expert knowledge should be implemented in separate components.
- Abstractions (frameworks): a bundle of related classes offers reuseable functionality, accessible by override- or delegation-mechanisms.
- Runtime binding (dynamic binding): when the criteria for loading a certain class(-graph) are not known at development time and must be deferred to runtime (e.g. you might not know on which GUI environment the application will run). The class graph created by a static factory is a component.
- Concurrency: one (type of) thread is one component.
- Global availability: when a piece of logic will be needed by a lot of other components everywhere across all architectural and environmental borders. I want to attach logging, access control and other cross-cutting concerns by adding a component. Can we call these "Commons"?
Complexity is a monster at the gate of chaos. What is a component? Where are the times we made it easy with building blocks?
_____________________________________________________________________________________
Keine Kommentare:
Kommentar veröffentlichen