A more layered-design would certainly make the core-code more accesible and easier to maintain. The following layers could be used (just an example):
Presentation: use components to create the actual blog, using skins;
Entities: all classes, like Item, Comment, Plugin, PluginOption, User, Blog, Nucleus etc. So a class would be created for every possible Nucleus entity, resulting in a more (well, complete) O-O design;
Components: the glue between these entities;
Data: this layer would handle all communication with the database and would be some sort of data abstraction layer so that it will be possible to change DBMS. Ideally this would be some persistancy framework like
Propel.
“One thing i would love to work on is a more layered design. From the first moment I opened ADMIN.php in my textedit I had the feeling it is seriously bloated. I'll give you an example of some design issues which are not very nice:
There is a COMMENT class which loads/saves one item, this is nice
There also is a COMMENTS-class which represents comments for one item, this is almost nice (i'll explain this shortly)
But then i see in ADMIN.php code which executes itself a query to get all the comments for one blog. This is *certainly NOT* the place where such code should go.
To illustrate, I created a diagram of how a nicer design could look:
I'll first explain my design and then explain how the previous example fits into it.
(Important: this design, currently, only pertains to the admin area)
In the design you'll notice 5 (actually 6) different layers (actually they could be divided into 'tiers'..)
Client-tier:
UI-layer: This is the user interface for the normal users with which they interact. However, it is not necesary that this be a weblayer. If we have a nice layered design, a rich-client (JavaScript?) could be created very easily.
Business-tier:
AdminService layer: this is the 'facade' interface to Nucleus. Everything you want Nucleus to do calls this layer. So, in fact, the UI-layer simply passes calls to methods at this layer. The AdminService layer, itself, only delegates function calls to the right components in the component-layer, which is the next layer.
Component layer: handles function calls for one specific set of functionality for example, everything related to items. I'm not completely sure about the AdminService and Componentlayer; for simplicity and performance I think it is acceptable to merge them.
Entity-layer: the layer containing the actual logic. Here you have object 'entities' like 'blog', 'item' etc. which represent one and only one instance of such an entity i.e. they are instantiated objects. They also have the responsability to save, load themselves. Also, there are 'entityhelpers'; these are used where you don't work with one instance of an entity, but with a collection of such entities i.e. the class, for example, all items of one blog.
Data-tier:
ADOdb-layer: this is our gateway to the database
database-layer: the actual database, by default mysql.
Now that's quite of a bit..
How does this relate to our example?
ADMIN.php currently has a lot of action_*-methods. Actually, these are already the methods that would be in the AdminService and/or components-layer. So, these methods would be split into a separate class which becomes the interface to the core.
COMMENT.php: all methods to load, save and delete a comment are moved into this class, thus giving 'a comment' responsabilities to update, load and delete itself. Currently, deleting and updating is done by the entity itself, but not saving, which is not so nice, as I discussed, earlier.
COMMENTS.php: instead of having the responsabilities to load comments for one single item it
also gets responsibilities to load other collections of comments; thus, in general, working with more than one comment (when only one comment is involved, is the responsability of the comment, itself). If these changes are made, the AdminService (thus in fact this is currently ADMIN.php) would simply have to ask COMMENTS to get all comments for a particular blog, instead of having to execute
SQL, itself. So, we get a strictly outlined set of responsibilities.
What are the advantages?
The code would become more easy to read and maintain … more modular, like self-contained “black box” objects. When calling a “black box” object, you don't have to care how that “black box” performs its function; you only have to supply its expected (contracted) inputs and handle its outputs. When you are working in one layer, you don't have to care about a lower/higher layer. For example, in the AdminService you don't care about
SQL, since that's a responsibility of a lower layer.
It is easy to add another UI, because it just has to delegate everything to the right method in the facade (AdminService) interface. For different UI's think about a webservice, a rich client,
XML-
RPC, Atom etc.
It becomes a lot easier to change the way data is stored: you only have to make modifications to classes of one layer (the object entity layer). Since a class only belongs to one class, you know which classes would be affected.
Creating unit tests is easier. I would love to have UnitTests for Nucleus. With a layered design, you can easily see for what functionality you have to test.
Of course, we don't have to create such a layered design from one day to another. We can modify, incrementally, until we attain a layered design (in contradiction to my previous idea ;)) However, this will be like walking through a minefield, hoping that nothing we touch blows up, because it implies that what we're modifying is modular and compartmentalized … and it isn't.
So, what I would propose for the roadmap:
first, start using ADOdb (now that I have looked at the docs etc., I like it.
then, start changing everything to a layered design (this can continue over different releases)
when, finally, all entities are responsible to save/load/delete themselves, let's add a simple persistancy framework (this is far from the same as persistent connections ;)). I have been thinking a bit on this and by adding one baseclass for our entities we could simply save/delete/update them without having to write any specific
SQL query :) also, plugin authors could use this by creating their own entity objects and letting them inherit from our base entity.
Of course, these are a lot of ideas; but, like I said earlier, I'm interested in modifying the core to use ADOdb and moving to a nicer layered design
These are part of the Nucleus 5 architecture plans. Read more about the project.