In order to do something useful with a programming language it is necessary to write code which calls upon the features available in that language. These features may either be provided in the core language or by add-on libraries. When writing applications which contain large numbers of components, where each component handles a different unit of work from the end user's perspective, the code which is written may be classed as either:
Other words I have seen to classify code in this way are:
The ratio between payload/plumbing or worker/navigation code can also be referred to as the signal-to-noise ratio (SNR).
A programmer will be perceived to be more productive if he can spend more time on the payload and less time on the plumbing. This will require access to additional functions, procedures or components which may be provided by either a library or a framework. These functions are in addition to the core language and provide code which has been written by someone else so that the programmer need not spend time writing his own version. It also saves time in that this pre-written code will (or should) have already been debugged, which is another task that the programmer can cross off his list.
I have used the words "library" and "framework", but what is the difference between the two?
In the world outside of software development a framework is some sort of support structure (e.g. exterior scaffolding or interior frame or chassis) which is used to help build other structures. The framework may be removed after construction, or it may become an integral part of the new structure. When building a software application it is also possible to use a software framework, but most of the "software frameworks" available today do not qualify to use the word "framework" in their names. This is because they do not actually offer any sort of support structure, instead all they are is a collection of loose parts which you have to assemble yourself. In my humble opinion they are libraries, not frameworks. The difference can be summarised as:
A definition of a framework can be obtained from several sources:
In the book Applying UML and Patterns, which was first published in 1997, the author Craig Larman writes the following:
38.4 What is a Framework?
At the risk of oversimplification, a framework is an extendable subsystem for a set of related services, such as:
- Graphical user interface frameworks (for example, Microsoft Foundation Classes, Smalltalk-80 Model-View-Controller).
- Persistence frameworks (that is, services to make persistent objects).
In general a framework:
- Is a cohesive set of classes that collaborate to provide services for the core, unvarying part of a logical subsystem.
- Contains concrete (and especially) abstract classes that define interfaces to conform to, object interactions to participate in, and other invariants.
- Usually (but not necessarily) requires the framework user to define subclasses of existing framework classes in order to make use of, customise, and extend the framework services.
- Has abstract classes that may contain both abstract and concrete methods.
- Relies on the Hollywood Principle -Don't call us, we'll call you.This means that the user-defined classes (for example, new subclasses) will receive messages from the predefined framework classes. These are usually handled by implementing superclass abstract methods.
Notice here that he specifically mentions the use of abstract classes, which are part of the framework, to provide invariant or unvarying parts of a logical subsystem. He then says that the framework user (that is, the developer) can extend the framework classes to use, customise and extend the framework services by defining subclasses. The use of abstract classes for invariant behaviour, subclasses for customisable behaviour, and the Hollywood Principle whereby the subclasses receive messages from the predefined framework classes come together and are expanded upon in the section on the Template Method Pattern which says:
38.11 Framework Design - Template Method Pattern
The next section describes some of the essential design features of the Database Brokers, which are a central part of the persistence framework. These design features are based on the Template Method GoF pattern [GHJV95].
This pattern is at the heart of framework design. The idea is to define a method (the Template Method) in a superclass that defines the skeleton of an algorithm, with its varying and unvarying parts. The Template Method invokes other methods, some of which are operations which may be overridden in a subclass.
Thus, subclasses can override the varying methods in order to add their own unique behaviour at points of variability.
The Template Method pattern illustrates the Hollywood Principle -Don't call us, we'll call you.
The Hollywood Principle is now formally referred to as Inversion of Control.
In the book Design Patterns: Elements of Reusable Object-Oriented Software which was first published in 1994 the authors wrote the following:
A framework is a set of cooperating classes that make up a reusable design for a specific class of software. For example a framework can be geared toward building graphical editors for different domains like artistic drawing, music composition, and mechanical CAD. ..... You customise a framework to a particular application by creating application-specific subclasses of abstract classes from the framework.
In my case my area of expertise is in the building of enterprise applications which are characterised by having web pages at the front-end, a relational database at the back-end, and software in the middle. This allows the user to put data into and get data out of the relational database while executing sets of different business rules. There may be several different business areas (domains) which are covered by the application, such as product data, order processing, invoicing, inventory, shipments, et cetera. Each of these is developed as a separate subsystem with its own database and its own set of tasks, but these subsystems are allowed to communicate with one another in order to share both processing and data.
It goes on to say the following:
The framework dictates the architecture of your application. It will define the overall structure, its partitioning into classes and objects, the key responsibilities thereof, how the classes and objects collaborate, and the thread of control. A framework predefines these design parameters so that you, the application designer/implementer, can concentrate on the specifics of your application. The framework captures the design decisions that are common to its application domain. Frameworks thus emphasize design reuse over code reuse, though a framework will usually include concrete subclasses you can put to work immediately.
Reuse on this level leads to an inversion of control between the application and the software on which it is based. When you use a toolkit (or a conventional subroutine for that matter), you write the main body of the application and call the code you want to reuse. When you use a framework, you reuse the main body and write the code it calls. You'll have to write operations with particular names and calling conventions, but that reduces the design decisions you have to make.
Not only can you build applications faster as a result, but the applications have similar structures. They are easier to maintain, and they seem more consistent to their users. On the other hand, you lose some creative freedom, since many design decisions have been made for you.
Later on it says:
Frameworks are becoming increasingly common and important. They are the way that object-oriented systems achieve the most reuse.
In a later section it describes the Template Method Pattern using these words:
Template methods are a fundamental technique for code reuse. They are particularly important in class libraries because they are the means for factoring out common behaviour in library classes.
Template methods lead to an inverted control structure that's sometimes referred to as "The Hollywood Principle" that is, "Don't call us, we'll call you". This refers to how a parent class calls the operations of a subclass and not the other way around.
In the article Applying Patterns and Frameworks to Develop Object-Oriented Communication Software (PDF), which was first published in 1997, the author Douglas C. Schmidt writes the following:
2.2.2 The Benefits of Frameworks
Although knowledge of patterns helps to reduce development effort and maintenance costs, reuse of patterns alone is not sufficient to create flexible and efficient communication software. While patterns enable reuse of abstract design and architecture knowledge, abstractions documented as patterns do not directly yield reusable code. Therefore, it is essential to augment the study of patterns with the creation and use of application frameworks. Frameworks help developers avoid costly re-invention of standard communication software components by implementing common design patterns and factoring out common implementation roles.
2.2.3 Relationship Between Frameworks and Other Reuse Techniques
Frameworks provide reusable software components for applications by integrating sets of abstract classes and defining standard ways that instances of these classes collaborate [Components, Frameworks, Patterns by Ralph E. Johnson]. The resulting application skeletons can be customized by inheriting and instantiating from reusable components in the frameworks.
The scope of reuse in a framework can be significantly larger than using traditional function libraries or conventional OO class libraries. The increased level of reuse stem from the fact that frameworks are tightly integrated with key communication software tasks such as service initialization, error handling, flow control, event processing, and concurrency control. In general, frameworks enhance class libraries in the following ways:
- Frameworks define "semi-complete" applications that embody domain-specific object structures and functionality:
Class libraries provide a relatively small granularity of reuse. In contrast, components in a framework collaborate to provide a customizable architectural skeleton for a family of related applications. Complete applications can be composed by inheriting from and/or instantiating framework components. This reduces the amount of application-specific code since much of the domain-specific processing is factored into the generic components in the framework.
- Frameworks are active and exhibit "inversion of control" at run-time:
Class libraries are typically passive i.e., they perform their processing by borrowing threads of control from self-directed application objects. In contrast, frameworks are active, i.e., they manage the flow of control within an application. This "inversion of control" is referred to as The Hollywood Principle, i.e., "don't call us, we'll call you."
The shortest definition I have seen can be expressed thus:
Libraries provide functions or APIs which are in addition to those provided by the core language. To make use of one of these functions the programmer must write his own code, or wrapper, to call the function, as shown in Figure 1:
Although this does help reduce the amount of code that a programmer has to write in order to perform a specific task in a single component, it does not help reduce by a significant amount the volume of plumbing code in an entire application which is comprised of many components.
Software Frameworks, on the other hand, are supposed to provide much more than a simple library of callable functions. The WikiPedia definition states the following:
In computer programming, a software framework is an abstraction in which software providing generic functionality can be selectively changed by user code, thus providing application specific software. A software framework is a universal, reusable software platform used to develop applications, products and solutions. Software frameworks include support programs, compilers, code libraries, an application programming interface (API) and tool sets that bring together all the different components to enable development of a project or solution.
It also identifies the following key distinguishing features that separate frameworks from normal libraries:
- Inversion of control: In a framework, unlike in libraries or normal user applications, the overall program's flow of control is not dictated by the caller, but by the framework.
- Default behavior: A framework provides basic default behavior from working templates.
- Extensibility: A framework can be extended by the user usually by selective overriding of a template or specialized by user code to provide specific functionality.
- Non-modifiable framework code: The framework code, in general, is not supposed to be modified, while accepting user-implemented extensions. In other words, users can extend the framework, but should not modify its code.
In order to provide these features it would be reasonable to assume the following:
Business-facing enterprise applications, which are not the same as public-facing websites and which have strict security requirements, may also need extra facilities such as the following:
In my opinion anything which calls itself a "framework" should also supply the following in its documentation:
If your framework does not have any of these then it could be a sign that it is not framework after all, but just a primitive collection of libraries which is masquerading as a framework.
A true framework is therefore a structure that provides wrappers for the program code, as shown in Figure 2:
How can such wrappers be provided? By giving the framework the ability to generate components for new tasks (user transactions) from predefined patterns or templates. These generated tasks will be fully functional, but with standard default behaviour. The components will have empty compartments into which additional code can be placed to enhance or replace the default behaviour. In Object Oriented Programming (OOP) the ability to have empty compartments can be provided by defining empty methods in an abstract superclass, which are called as part of the normal processing sequence, so that each subclass can override the empty method with its own specific code. Each of these methods will be visited at the appropriate time in the processing sequence, and any code found will be executed.
If you have something which calls itself a framework, but it does not have a discernible structure, does not have any pre-compiled components, does not generate any wrappers for your code, does not provide any means to execute the code you have generated, and forces you to write a lot of plumbing code yourself, then it is not a true framework but a simple library.
Note here that while Inversion of Control (IoC) has come to mean different things to different people, I prefer to use the first definition which can be found in Designing Reusable Classes which was published in 1988. It contains the following:
One important characteristic of a framework is that the methods defined by the user to tailor the framework will often be called from within the framework itself, rather than from the user's application code. The framework often plays the role of the main program in coordinating and sequencing application activity. This inversion of control gives frameworks the power to serve as extensible skeletons. The methods supplied by the user tailor the generic algorithms defined in the framework for a particular application.
A framework's application specific behavior is usually defined by adding methods to subclasses of one or more of its classes. Each method added to a subclass must abide by the internal conventions of its superclasses.
This principle has come to be known as the Hollywood Principle (don't call us, we'll call you) which was first used in a paper by Richard E. Sweet which was published in 1985. In the books which I referenced earlier, one by the Gang of Four and the other by Craig Larman, they both mention the Template Method Pattern as being the best design pattern for implementing inversion of control. This pattern plays a fundamental role in my framework as I have a single abstract class which is inherited by every Model class. The abstract class contains concrete invariant methods and empty "hook" methods which can be redefined in any subclass.
This is not to be confused with the Dependency Inversion Principle (DIP) which uses different objects instead of different method implementations in subclasses.
RADICORE is a true framework because it has a structure instead of being just a collection of loose parts, and that structure can be shown in a simple structure diagram and UML diagrams. Other pseudo-frameworks either don't have what can be recognised as a structure, or it is so complicated that it cannot fit into a single diagram.
The distinguishing features which separate a framework from a library are provided in the RADICORE framework as follows:
Note here that these distinguishing features are provided by a combination of reusable Page Controllers which call standard methods on whichever Model they are instructed to work with. Each of these standard methods is an implementation of the Template Method Pattern which defines a mixture of invariant and variant methods. All the invariant methods are defined in the abstract table class and contain default behaviour while the variant or hook methods, which are also defined in the abstract superclass but are initially empty, allow different implementations to be defined in each subclass.
The RADICORE framework contains the following pre-compiled components and supporting databases:
The RADICORE framework is based on a combination of the 3-Tier Architecture with its Presentation, Business and Data Access layers, and the Model-View-Controller design pattern. The Controllers, Views and Data Access Objects are provided by the framework as application-agnostic services. Each individual subsystem or subdomain has its own database which then requires a separate Model class for each table which exists in the business/domain layer. All HTML output is generated from a standard View module which first copies the data, some of which is supplied by the framework and some by the application, into an XML document and then transforms it into HTML using an XSL stylesheet.
This combination of 3-Tier Architecture and Model-View-Controller is shown in Figure 3:
Figure 3 - Model-View-Controller plus 3-Tier Architecture
Note that the small boxes in this diagram do not represent single components but types of component, and each type has a different number of alternatives which are chosen at runtime:
The RADICORE framework implements inversion of control by implementing the Template Method Pattern. This is done by providing a single abstract table class which is then inherited by every concrete table class. Every public method is an instance of a Template Method in that some steps are provided by invariant/fixed methods in the superclass while other "hook" methods, which are initially empty and so do nothing, can have different implementations defined in each subclass.
When developing a large application which deals with several different business domains, such as Orders, Invoices, Shipments and Inventory, a novice developer may think that as each domain requires its own separate database and set of user transactions to manipulate the contents of that database that there would be few components in the framework which could be shared by any of those domains. When you consider that it is only the Model classes which should contain the business rules for each domain, this means that every other component - Controllers, Views and DAOs - should be domain-agnostic and therefore sharable. I use the word should as I have yet to see any other framework which offers this capability. In Radicore they are completely sharable. Each Controller can be instructed to communicate with any Model, each View can extract the data from whichever Model it is given and concert it to HTML, and each DAO can be instructed by any Model to communicate with its database.
Using the RADICORE framework it is possible to take a database table's structure, import it into the Data Dictionary, export the class file, generate the task and then run it without having to write a single line of code - no PHP, no SQL, no HTML. When you run the Generate PHP script task in the data dictionary for LIST1 or LIST2 patterns as well as creating the component script and screen structure file it will also create entries on the MENU database so that the task will immediately appear on a menu button, and the task's children, the ADD, ENQUIRE, UPDATE, DELETE and SEARCH screens, will appear in its navigation buttons. The new task can be run simply by pressing its menu or navigation button.
Although the generated tasks start out by being quite simple, the screen structure files can be modified to alter what data is displayed and where it is displayed, and the table class files can be modified to add whatever additional processing logic is required. Each table class inherits all its methods from the abstract table class, and this abstract class contains a series of customisable methods which are deliberately empty. Each of these methods is called at a particular point in the processing sequence, but as they are empty they do nothing. All the developer has to do to have his own code processed at that point in the sequence is to copy the empty method into his table class and fill it with the relevant code. The non-empty method will then be executed instead of the default empty method.
Each table class is responsible for the data validation and processing of business rules for a single table in the database. The table class file, as created by the Data Dictionary, starts off by being very small as all it needs to identify is the database name, the table name and the table structure (column names and data types), which is actually included from a separate file. All the remaining code is inherited from an abstract table class. Each user transaction executes a number of predetermined methods in a particular sequence. All of these methods are defined within the abstract table class, but some of them are deliberately empty and can be overridden in the concrete table class in order to provide custom code.
The generated table class is capable of handling the basic CRUD (Create/Read/Update/Delete) operations on that table, including proper data validation, without the need for any additional code. However, this basic behaviour can be overridden or enhanced to include whatever custom processing is necessary. Just copy an empty customisable "hook" method from the abstract table class, fill it with code, and that code will be executed at a set point in the processing sequence. For example, by default the class will read from and write to a single database table, but this can be changed so that you can read from multiple tables, either by modifying the SELECT statement to include JOIN clauses, or by inserting code to read from other tables after the original SELECT statement has been processed. Writing to multiple tables involves inserting custom code in either the _cm_post_insertRecord() or _cm_post_updateRecord() methods.
Note that the table class exists in the Business layer, so does not construct and execute any SQL queries as this is the responsibility of the Data Access layer.
If a table's structure is ever altered it can be re-imported into the Data Dictionary and re-exported to the application. In this case it is only the table structure file which is overwritten as the class file may contain custom code.
The component script which is generated is actually quite small, usually containing no more than three lines:
The screen structure file identifies which column goes where on the screen, but the actual building of the HTML output is handled by a pre-written and reusable XSL stylesheet. Each controller automatically calls a standard function which extracts all the column data from a table object and inserts it into an XML document which is then transformed into HTML by the XSL stylesheet.
While the generated tasks will perform all the necessary functions to view and maintain the contents of a database table, it may sometimes be necessary to override the defaults with some customisations. This can be done in several ways:
In order to qualify for the title of "framework" a product should have the following attributes:
If the product you are using does not have all of these attributes then does it really deserve the title of "framework"?
A proper framework should greatly reduce, or even eliminate altogether, the amount of code that needs to be written to perform standard "plumbing" tasks, thus leaving the developer with more time to spend on the valuable "payload". One of the early users of the RADICORE framework was amazed at how much code he did not have to write.
If you have something which calls itself a framework, but it does not handle all of this "plumbing" automatically, and you have to write a lot of code yourself, then it is not a true framework but a simple library.
|11 Jun 2020||Updated What is a Framework? with a reference to a definition from Douglas C. Schmidt.|
|09 May 2020||Updated What is a Framework? with a reference to a definition from the Gang of Four.|
|28 Apr 2020||Added What is a Framework? with a reference to a definition from Craig Larman.|
|16 Apr 2020||Added The meaning of "Inversion of Control (IoC)"|