Очевидно время разработки спешит, зачем мне рефакторить весь проект

программист

последний разAppКогда интерфейс версии итерируется, старый интерфейс проекта, который поддерживался в течение двух лет, подвергается рефакторингу Вот краткое объяснение процесса рефакторинга в этой статье:

Зачем проводить рефакторинг

Прежде всего, давайте поговорим о том, зачем нужен рефакторинг, ведь он поддерживается уже два года, прошел много итераций разработки, почему рефакторинг в этот раз?

Это должно сначала объяснить, что происходит с нашим проектом интерфейса.

Обычно одинAppЕсли проект более сложный, то интерфейс можно разделить на несколько проектов.AppТо же самое, и этот проект, который я рефакторил, также является относительно новым интерфейсом модуля.Поскольку он был относительно простым в начале, я не выбрал текущий зрелый фреймворк, а использовалPHPЯ написал простойMVCFramework, собственно, структура каталогов проекта примерно следующая:

controlers #控制器层
models #模型类层
common #公用函数
config #配置文件目录
libs #基础类库
ext #第三扩展
index.php #入口文件

Как видно из структуры кода проекта, наиболее важными являются слой контроллера и слой модели:

Уровень контроллера (controllers): Отвечает за получение параметров запроса, а также накапливает много бизнес-логики, одновременно вызывая класс модели для завершения бизнес-логики, возвращая данные, вcontrollersкаталог, из-за различныхAppверсия предоставляет интерфейс, поэтому формат подкаталогаv1.x.x, чтобы различать разные версии интерфейса.

controllers
    v1.0.0
    v1.0.1
    ...
    v5.0.0

модельный слой (models): уровень бизнес-логики, который также включает обработку данных.CURD, вызов третьей стороны, проверка параметров и другие функции, почти все бизнес-функции находятся здесь, и уровни модели разных версий вызывают друг друга, поэтому этот уровень также является уровнем с наиболее запутанными функциями, поэтому это также уровень, который нуждается в реконструкции в наибольшей степени.modelsВерсия каталога иcontrollersпохожие, разные версииmodelКлассы содержат много повторяющегося кода.

models
    v1.0.0
    v1.0.1
    ...
    v5.0.0

Благодаря приведенному выше введению вы на самом деле обнаружите, что это проект, который слишком прост, чтобы быть простым, но независимо от того, насколько прост проект, с развитием бизнеса и многократной итеративной разработкой код кода чрезвычайно хаотичен. , которые можно резюмировать следующим образом.

  • Без хорошей иерархии каталогов это в основном простое разделение уровня контроллера и уровня модели.Вся бизнес-логика сложена в уровне контроллера и уровне модели, и нет никакой расширяемости.

  • Многие конфигурации напрямую жестко закодированы в коде.Хотя в проекте есть каталог, предназначенный для хранения конфигураций, все еще есть много конфигураций, которые напрямую жестко запрограммированы в коде, например подключениеredisкод.

  • Не существует стандарта кодирования, независимо от имени переменной, константы или имени класса, имена очень произвольны.

  • Код также наполнен множеством магических значений.Как будет у нового человека вступать во владение будет совершенно непонятно, что эти значения означают.

  • Все коды не имеют журнала вывода, появляютсяBUGтрудно локализовать проблему.

  • Бизнес-код накапливается непосредственно на уровне управления и уровне модели, а общедоступный код не извлекается.При добавлении интерфейса новой версии необходимо полностью скопировать код предыдущей версии.

  • вообще не используетсяPHPПространство имен не очень хорошо разделяет разные классы.

Короче говоря, это чрезвычайно простая структура проекта, но код стал чрезвычайно хаотичным и нестандартным приложением из-за обслуживания слишком большим количеством людей.Хотя я занимался рефакторингом проекта с тех пор, как принял его, это была только итерация отдельных интерфейсы ранее. , в то время как в самом последнемAppПри итерации практически все интерфейсы являются новыми версиями, поэтому рефакторинг неизбежен, даже если не хватает времени, на более поздние версии.

процесс рефакторинга

Выше перечислены некоторые проблемы проекта, по сути, процесс рефакторинга заключается в оптимизации поднятых выше проблем.

Цель рефакторинга

  • Повторно разделите структуру проекта, чтобы сделать иерархию структуры проекта более ясной.

  • При итеративной разработке версий нет необходимости копировать один и тот же код, что повышает эффективность разработки.

  • Повышение ремонтопригодности кода.

принципы рефакторинга

  • Принцип единой ответственности: функция каждого класса должна быть единственной, и функция каждого метода должна быть единственной, чтобы избежать раздувания кода.

  • соглашение об именах переменных

  • Избегайте написания магических значений прямо в коде

  • При переборе интерфейса и добавлении новой версии интерфейса не обязательно полностью копировать код интерфейса предыдущей версии.

Повторно разделенная структура проекта

controllers # 控制器层,只能将参数传递给services层。
    v1_0_0
        IndexController.php
    v1_0_1
    ......
    v5_0_0
services #具体业务逻辑层,可以调用manager层或models来实现业务逻辑
    v1_0_0
    v1_0_1
    ......
    v5_0_0
handlers # 扩展层,对services的补充
models # 模型,针对数据表的CURD代码
entity #实体类
managers #业务封装层 
libs #类库
ext #第三方类库
common #公用函数
index.php #入口文件

Ниже приведен скриншот структуры каталогов проекта:

一个controller类的示例:

namespace app\controllers\v1_0_0;
use app\services\v1_0_0\IndexService;

class IndexController {
    private $service = null;
    public function __construct(){
        $this->service = new IndexService();
    }
    
    public function actionIndex(){
        //接收参数
        ....
        调用IndexService的业务方法,并返回值给客户端
        return $this->service->index();
    }
}

一个service类型的示例:

# 不同版本的service之间通用代码抽取到Service类,作为基类被继承

namespace app\services;

class IndexService{
    
    public function __construct(){
        
    }
    
    //业务方法
    public function index($page = 1){
        //具体业务逻辑
        $list = $this->getArticle();
        return [
            'list' => $list,
            'total' => 100
        ];
    }
    
    protected function getArticle(){
        
    }
}

В процессе рефакторинга важным соображением для проектирования структуры каталогов, показанной выше, является то, что при добавлении новой версии интерфейса логика предыдущей версии может быть повторно использована в максимальной степени.Новый интерфейс здесь означает, что текущий версия интерфейса домашней страницыv1.0.0, но из-за итерации версии интерфейс будет обновлен доv1.0.1, то есть апгрейд интерфейса.

Есть две причины для обновления интерфейса:

  • Логика бизнес-процессов интерфейса изменилась, поэтому интерфейс необходимо обновить.

  • Структура данных интерфейса меняется, например новые данные или типы данных, поэтому интерфейс необходимо обновить.

Например,indexинтерфейс изv1.0.0Обновитьv1.0.1час,getArticle()Структура данных метода или бизнес-логика меняются, в это время интерфейс родительского класса наследуется и перезаписывается.getArticle()метод.

namespace app\services\v1_0_1;
use app\services\IndexService IndexBaseService; 

class IndexService extends IndexBaseService{
    
    public function __construct(){
        
    }
    
    //重写覆盖父类逻辑
    pulic function getArticle(){
        
    }
}

Но в это время вы найдетеgetArticle()Логика переопределения метода, только вv1.0.1В этой версии, если логика этой перезаписи одинакова в последующих версиях, разве ее не нужно переписывать в каждой версии?

В настоящее время эта логика может быть извлечена и повторно использована для каждой требуемой версии.Если имеется отдельная логика обработки, можно использовать метод переопределения, а извлеченную логику можно поместить в каталог обработчиков.handlersкаталог правильныйservicesУровень абстракции, который необходимо переписать и повторно использовать в нескольких версиях.

Итак, мы положилиgetArticle()Метод извлекается следующим образом:

namesapce app\handlers;

trait getArticle{
    
    public function getArticle(){
        
    }
} 

В этот моментv3.0.1Интерфейс, который загружает методы вышеперечисленных обработчиков, полностью логически переиспользуется.

namespace app\services\v3_0_1;
use app\services\IndexService IndexBaseService; 
use app\handlers\getArticle;

class IndexService extends IndexBaseService{
    
    use getArticle;
    
    public function __construct(){
        
    }
}

результат рефакторинга

Честно говоря, времени на разработку проекта не хватает, да и мои личные возможности тоже ограничены, поэтому я могу только сделать все возможное, чтобы улучшить всю структуру проекта в этой разработке.Многие несовершенства можно оптимизировать только в последующей разработке. .

Преимущества после рефакторинга

По сравнению с первоначальным все деловые накопления вmodelsСлои, разделенная архитектура, каждый слой отвечает только за свои дела, поэтому логика относительно понятна, код ремонтопригоден, а ответственность каждого класса или метода едина, что снижает сложность разработки.

Недостатки после рефакторинга

Конечно, исходный код очень прост, простоcontrollersслой напрямую вызывает слой моделей, а иногда вся бизнес-логика пишется непосредственно вcontrollerслой, после рефакторинга соответственно возрастет сложность кода.

Зачем проводить рефакторинг вместо разработки нового проекта?

Многие могут спросить, а не лучше ли переделывать такой простой проект напрямую? На самом деле так оно и есть.Кроме перепрошивки в вышеописанном рефакторинге, в проекте еще много общего кода и модулей.Если проект предстоит переделывать, то эти базовые тоже надо перезапускать, а старые проекты тоже нужно продолжать поддерживать и увеличивать.Стоимость разработки и сопровождения, поэтому рефакторинг - более подходящий выбор.

резюме

Честно говоря, проект интерфейса, который я рефакторил, совсем не сложен, основной код по-прежнемуCURD, нет очень сложной бизнес-логики, но, поскольку с самого начала нет строгой многоуровневой структуры кода, в начальном процессе нет последовательной спецификации кода, что приводит к двум или трем годам бизнес-развития и итеративной разработки кода, в результате чего код Путаница и дублирование бизнес-логики накапливаются.

Таким образом, для любого проекта хорошее разделение кода и спецификации разработки имеют основополагающее значение для обеспечения ремонтопригодности проекта.


Если вы считаете, что статья хороша, отсканируйте код, чтобы следовать ему. Ваше внимание — самая большая мотивация для моего письма.