From an ugly duckling to a swan, or how to fix a curved-handed code

    image

    What is it about?


    Many begin to write a project to work with one small task, not implying that this story will lead to a multi-user management system, let's say, content or, by the way, production. And everything seems cool and cool, everything works until you begin to understand that the code that is written consists entirely of crutches and hardcode. There is an urgent problem: when adding a new feature, you have to mess with this code for a very long time, remembering “what was written there that was?” and curse yourself in the past. In particular, this article is intended for beginner developers who do not need the refactoring at the first stage, but today they are in an unpleasant situation.

    Suppose we have a hard code at the entrance with typesetting, queries, crutches, sometimes even unreadable.

    How does it help


    What will the system gain as a result of refactoring?
    - Structured and modular code.
    - Separation of UI and logic.
    - Ability to write UNIT tests.
    - Ability to write APIs only for authorized applications in the API.
    - A simpler approach to transferring to another database.

    A particular example of the case is 'how to do it and where to start?'. I propose to deal with such corrections sequentially, and at the same time, without completing the second stage, do not begin to take on the third. We will correct the code in the working system, it is better to write functional tests in advance in order to understand that everything works as it should.

    Stages


    1. Algorithmic approach .
    Let’s take a look at our awful layout-proof source code that can not be tested (and probably repeated in other places). Simple and straightforward, but the sequence of such code - creates a bunch of known troubles.

    index.php

    Пользователи

    query(‘SELECT * FROM users LIMIT 10’); if($DB->get_num_rows()){ while($user = $DB->fetch_row()){ echo ‘

    ’.$user[‘name’].’

    ’; } } ?>


    2. The procedural approach .
    Why not write a function and call it elsewhere in the system? The transition to procedural programming will help to reduce the code, although using the example of 1 call, it looks worse.

    functions.php
    $DB = new DBConnector
    function GetUsers(){
        global $DB;
        $DB->query(‘SELECT * FROM users LIMIT 10’);
        if($DB->get_num_rows()){
            while($user[] = $DB->fetch_row());
        return $users;
        } else {
         return array();
        }
    }
    ?>
    


    index.php

    Пользователи

    ’.$u.’

    ’; } ?>


    Comment: Already better. If you translate all requests to this form, then you will definitely get a list of certain functions.php that work with some module. Thus, the model is already separated from the UI and each function can be tested, as well as the sequence of calls to such functions.

    3. Object oriented approach .
    Why is it necessary to connect all the functions in the system if it is enough to work only with the necessary set of functionality? For example, on a page with a simple list of users - there is no need to connect the entire list of functions, such as a task, or a project. Why not create a class of work with a module, from which an object of work with only this module will be created? You can build the architecture so that the inheritance of the functions of the same parameters of the Get (add / edit) methods will simply be inherited from some superclass that generates classes for working with modules. Also, there is a possibility that it will not always be necessary to access the database for any functionality, so we can even connect to it.

    We will write a basic abstract superclass that will connect to the database and have a method of obtaining a list of some records. We inherit the class of working with users from it, create an object and get records.

    Baseclass.php
    abstract class BaseClass{
        protected $dataBase;
    protected $moduleName;
        function __construct(){
        $this->dataBase = new DBConnector;
    }
    // Наша функция получения списка с заданием количества
    function Get($limit=10){
         $DB->query(‘SELECT * FROM ‘.$this->moduleName.’ LIMIT ’.$limit);
         if($DB->get_num_rows()){
            while($user[] = $DB->fetch_row());
            return $users;
         } else {
            return array();
         }
        } 
    }


    UserClass.php
    include ‘BaseClass.php’
    class UserClass extend BaseClass{
          function __construct (){
              parent::construct(‘users’);
         }
    }
    


    index.php

    Пользователи

    get(); //например так foreach($users as $u) { echo ‘

    ’.$u.’

    ’; } ?>


    Comment: Better, albeit a lot of code, right? The fact is that these two classes are the first step to writing an API. Why is that? The fact is that requests through the RESTFull API are made at the address and very often there are module names. Depending on the address, you can connect a class (or connect a ClassLoader, since they are now a dime a dozen) and call the set of functions that is allowed for this user (you can insert a rights or role handler, but that's another story).

    Salt


    The essence of the article is that refactoring is almost always possible and often necessary even in the most hopeless situations. Everyone loves beautiful code, but often there is no time to write it, and undoubtedly this is bad practice.

    In this case, 3 stages are given, as a result of which, the system will receive the separation of the UI from the application logic. This will prepare your system, overloaded with crooked code, for the possibility of writing Unit tests, writing a RESTfull API, and a sense of self-satisfaction for the work done. For many - this, of course, may be obvious, but when asked to write a third-party application, or provide an API, sometimes you have to blush.

    PS: I will be glad to any comments and, possibly, links to other methods and solutions to problems of a similar nature.

    Also popular now: