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:
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 has a default behavior. This default behavior must be some useful behavior and not a series of no-ops.
- Extensibility: A framework can be extended by the user usually by selective overriding 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.
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 that this inversion of control can be provided by an implementation of the Template Method Pattern in which empty "hook" methods, along with non-empty concrete methods, can be defined in an abstract class but overridden in a subclass in order to provide a different implementation at run-time. This is discused further in How Radicore's Hook System Works.
The RADICORE framework contains the following pre-compiled components and supporting databases:
The RADICORE framework contains an implementation of the 3-Tier Architecture which has three separate and distinct layers:
This combination of 3-Tier Architecture and Model-View-Controller is shown in Figure 3:
Figure 3 - Model-View-Controller plus 3-Tier Architecture
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.