Back to Home

Layered architecture based on the yii framework

Imagine a company that sells a number of its own products - both for external users and for internal users. Most likely · each product will not be able to exist ...

Layered architecture based on the yii framework


    Imagine a company that sells a number of its own products - both for external users and for internal users. Most likely, each product will not be able to exist separately, like a spherical horse in a vacuum, and to some extent will be integrated with others. As a result, all of them together form a certain layer of interconnected and at the same time independently developing organisms. And most likely, their development is carried out by completely different teams.

    Good examples of such an environment are Yandex (search, Direct, maps, mail, vertical and internal services) or Google. It is clear that the listed giants have technologies in each product, but if we take a smaller company and work in a narrower subject area, we can assume that the web products will be executed on the same technologies (programming languages, frameworks, etc.).

    It is about the experience in organizing the architecture of the entire product line of such a company that I want to tell.

    Our external web products are an online version , an open reference API and a cartographic, feedback service . Internal: CRM, billing, algorithmic calculations, systems of statistics and
    export-import data.

    We will derive two concepts:

    Web infrastructure - a set of web products of a company, interconnected and working in related subject areas.

    Technological base - a single code base for the company's web infrastructure. It contains a set of software blocks with a high and low level of abstraction. High-level blocks are the entities already developed by the team of developers in the subject area of ​​the company. Low-level blocks are, for example, a set of libraries or frameworks.

    Surely more than once each of you has worked on several projects and implemented modules, which you then reused in the next project. This does not always go smoothly: a completely separate version of the module is formed in a separate SVN branch, and then in the third project it is necessary to apply something in between the first two versions of the module, etc., etc. In other words, if you do not list all the problems, these are the quality criteria of the technological base. Let's denote them:
    • Reuse of modules and components between projects;
    • the extensibility of the functionality of already written modules without rewriting the entire system;
    • unified product deployment scheme;
    • load scalability.

    Our goal was to create such a web infrastructure. The first thing we started with is the preparation of the technological base. We have selected the following frameworks and technologies:
    • PHP
    • application framework - yii;
    • framework for deployment and application deployment - phing;
    • framework for writing unit tests - phpUnit;
    • continuous integration system - Jenkins;
    • functional and UI testing - Selenium;
    • DBMS Postgres;
    • key-value storage memcached, redis;
    • nginx web server.

    (Why we will choose these systems, we will not discuss it, this is a topic for a separate publication.)

    To ensure the quality criteria of the technological base, we decided to lay down a layered architecture.
    A layered architecture is such a system architecture in which the system consists of some ordered set of software subsystems called layers, such that:
    • on each layer nothing is known about the properties (and even the existence) of subsequent (higher) layers;
    • each layer can interact to control (access components) with the immediately preceding (lower) layer through a predetermined interface, not knowing anything about the internal structure of all previous layers;
    • Each layer has certain resources that it either hides from other layers, or provides some of their abstractions directly to the next layer (through the specified interface).

    Thus, in a layered software system, each layer can implement some data abstraction. The relations between the layers are limited by transmitting the values ​​of the parameters of the inversion of each layer to the layer adjacent from below and the output of the results of this inversion from the lower layer to the upper one. Using global data in multiple layers is not allowed. A more complete definition can be found in the works of Fowler .

    Without considering the network and servers, which in themselves are separate layers, we consider the device technological platform. Three layers can be distinguished in it:


    Fig. 1. Layers technology platform architecture of

    Fig. 1, three layers are highlighted:
    • Core layer - core layer. It hosts common low-level libraries and frameworks. For example, yii.
    • Shared layer - a layer of modules that implement some kind of system functionality that can be used in several projects.
    • Application layer - application layer. At this level are all applications with their specific modules.

    At the same time, the important point is that the modules should be able to easily move from the application layer to the level of common modules. The explanation is very simple: when a new project starts, the most necessary functionality is usually implemented. As the project develops, it begins to grow into ties with other products (for example, they decided to pull reviews from one project to the cafes on our other project), and, perhaps, some of the modules may be required for other projects. Or the project is divided into parts, and the modules are divided into several applications.

    Let us consider in more detail the file organization of the application in the Application layer, taking into account the specifics of yii.

    application
     	framework - the framework is deployed here
     	lib - components from core and shared. Separate alias for this folder in Yii config		
    		components
    		extensions
    		...
    	protected
    		components
    		extensions
    		...
    	public
    	themes
    	config
    

    Figure 2. File organization of the yii application.

    As we can see, there are components and extensions both at the application level and at the general level (shared). Here is the structure of an application already assembled from the repository. Of course, everything can be organized differently in the version control system. For example, we have two build modes, when everything is poured into the application folder and when symlinks to the extension library are made. The first is necessary to isolate different applications, when we cannot separately upgrade extensions without updating all applications, and to deploy multiple instances on the same machine. Or deploying different branches on the same server. The second is convenient for developers when working with code.

    So, we set a flexible foundation for our web infrastructure, but is that enough? Not. Two important things are missing:
    • application architecture should be weakly meshing and shared;
    • deployment system and product assembly.

    Now for each item in more detail.

    Application architecture


    The application architecture will also be based on layers. We

    distinguish the following levels: Figure 3. Layers of a yii application

    A layer of thin controllers contains a minimum of logic and operates on the extension APIs. The business logic layer consists of the extension layer and the data model layer. The layer of Yii extensions and data models have a very strong degree of connectivity, this is shown by a thicker arrow in the diagram.

    The greatest degree of connectivity exists between the application and the thin controllers. The probability of reuse is minimal. But the connection between the layer of “thin” controllers and the layer of business logic needs to be done as little as possible, since we can and must reuse business logic in our other applications. And we can do this with the flexibility of Yii and its config.

    The config connects the set of components and extensions we need. An example of connecting an extension:

    'geoip'  =>  array ( 'class'  =>  'application.extensions.GeoIP.CGeoIP' ) ,


    The initialized extension in the application can be accessed using the geoip key. For example:

    Yii :: $ app -> geoip ;


    The first time you access the component, the CGeoIP class initializes. Flexibility lies in the presence of a key :-) We can at any time through the config to replace the implementation, and the application will continue to work on the geoip key.

    Based on this flexibility, we can easily manage the connectivity between the application and the layer of business logic.

    By grouping the logic of working with a certain application essence into extensions, we make it separable. All models are thus encapsulated in the extension and the application controller works with the data through the extension API.

    Extensions are an additional level of abstraction for us, behind which we can hide the data sources necessary for the internal work of various extension API methods.

    Let's fantasize a bit and come up with an application:


    Figure 4. Example architecture of a yii application

    Our application works with several extensions. Extensions operate on a dataset and are closely related to the model layer. An important point: the degree of bonding between layers of honey increases from top to bottom. The data models are most closely related.

    Now let's imagine that there was a need to create a single user authorization service for all products. We can easily implement such a project as a separate application. To work with the new application, we write the extension - the rest client UserServiceRestClient. The client will have the same API as the UserExtension API. We look at the picture for clarity: Fig. five




    We place UserServiceRestClient in the shared level and change the class to be used in the application config. Since the API is the same, the implementation has been changed without changing the code. Very flexible! All other applications also work with the user service using UserServiceRestClient.

    So, we figured out the architecture, but with this approach the application config will be rather big. Using your hands to register all the dependencies for the application is not at all Jedi. Especially when the project lives and database migrations also appear. All these issues can be resolved with the help of our build system and product deployment.

    Deployment and assembly system


    What should the deployment system do:
    • deliver code to the specified directory on the server;
    • pull up all application dependencies (shared level extensions and framework);
    • generate application config;
    • Perform sql database migrations.

    And also - the task of running unit-tests, building debug-versions of the project, etc. I don’t list everything, it’s a matter of taste, and quite a lot of attention has been paid to all these operations on the Internet. For example, our deployment system configures related software like nginx, Sphinx, RabbitMQ and creates documentation. Conveniently!

    In general, the tasks are ordinary: file operations, working with version control systems, launching third-party utilities (PHPUnit, for example, or Doxygen), etc. Attention should be paid to config generation. We made it according to the template with the meta-configuration file:

    application
    	protected
    		config
    		main.php.template - yii config template
    	public
    	themes
    	build.prop - meta configuration file
    	build.xml - phing'a config

    fig. 6

    When generating the config, Phing parses the template and replaces all placeholders with the appropriate parameters specified in the meta-configuration file. It turned out very convenient. All application dependencies are set in a meta-config:

    ## List of extensions, components and etc. to install ##
    EXTENSIONS = myExt, myExt2
    COMPONENTS = component1, component2
    HELPERS = myHeper, myTextHelper
    COMMANDS =


    Also, databases, paths, hosts are registered in the meta-config - in general, that's all. An additional convenience for automation, again, is that all these parameters can be passed to the Phing command line and redefined. And in the future, for example, to organize the assembly of packages for your * nix OS.

    Thus, the meta-configuration file is a layer of abstraction from the format and number of configs in our application.

    As a result, Yii configuration flexibility + build system = easily configurable and assembled products.

    Total


    So, what did the experience of using such a work scheme during the year show us?
    • If it becomes necessary to reuse some extensions, then this will not become a problem, the process of continuous integration has also been built without any special problems.
    • There is a necessary margin of flexibility that makes it easy to develop and expand the functionality of applications. Function blocks can be done extremely quickly without thinking about the performance and quality of the code.
    • If the interface is thought out, you can always fearlessly complete the functionality, improve performance, change the data warehouse and carry out refactoring.
    • A well-thought-out deployment system of the application allows you to quickly deploy the system for testing and minimizes errors when deploying to battle servers related to human inattention.
    • Due to the isolation of individual functional modules, you can always select a separate development group to work with it. This allows us to solve the problems of the growth of the development department and not to turn into a large uncontrolled collective farm, where everyone works on everything, and thereby only interfere with each other.


    PS And yes, we are looking for yii-developers in Novosibirsk and Kiev. Come! :-)

    Read Next