Какова лучшая практика для архитектуры слоев?

Сейчас я работаю над очень крупным банковским решением, разработанным в VB6. Приложение в значительной степени основано на формах и не имеет многоуровневой архитектуры (весь код для доступа к данным, бизнес-логики и манипулирования формами находится в одном классе форм). Моя работа сейчас заключается в рефакторинге этого кода. Я пишу правильный уровень бизнес-логики и уровень доступа к данным в C#, а форма останется в VB.

Вот фрагменты кода:

public class DistrictDAO
{
    public string Id{get;set;}
    public string DistrictName { get; set; }
    public string CountryId { get; set; }
    public DateTime SetDate { get; set; }
    public string UserName { get; set; }
    public char StatusFlag { get; set; }
}

Район Entity class, почему его расширение - DAO, мне непонятно.

 public class DistrictGateway
{
    #region private variable
    private DatabaseManager _databaseManager;
    #endregion

    #region Constructor
    public DistrictGateway(DatabaseManager databaseManager) {
        _databaseManager = databaseManager;
    }
    #endregion

    #region private methods
    private void SetDistrictToList(List<DistrictDAO> dataTable, int index, DistrictDAO district){
        // here is some code for inserting 
    }    
    #endregion

    #region public methods
        try
        {
        /*
         query and rest of the codes
         */    

        }
        catch (SqlException sqlException)
        {
            Console.WriteLine(sqlException.Message);
            throw;
        }
        catch (FormatException formateException)
        {
            Console.WriteLine(formateException.Message);
            throw;
        }
        finally {
            _databaseManager.ConnectToDatabase();
        }


    public void InsertDistrict() { 
        // all query to insert object
    }

    public void UpdateDistrict() { 

    }
    #endregion
}

Класс DistrictGateway, отвечающий за обработку запросов к базе данных Теперь бизнес-уровень.

  public class District
{
    public string Id { get; set; }
    public string DistrictName { get; set; }
    public string CountryId { get; set; }
}


public class DistrictManager
{
    #region private variable
    private DatabaseManager _databaseManager;
    private DistrictGateway _districtGateway;
    #endregion

    #region Constructor
    public DistrictManager() { 
        // Instantiate the private variable using utitlity classes
    }
    #endregion

    #region private method
    private District TransformDistrictBLLToDL(DistrictDAO districtDAO) { 

        // return converted district with lots of coding here
    }

    private DistrictDAO TransformDistrictDLToBLL(District district)
    {

        // return converted DistrictDAO with lots of coding here
    }

    private List<District> TransformDistrictBLLToDL(List<DistrictDAO> districtDAOList)
    {

        // return converted district with lots of coding here
    }

    private List<DistrictDAO> TransformDistrictDLToBLL(List<District> district)
    {

        // return converted DistrictDAO with lots of coding here
    }


    #endregion

    #region public methods
    public List<District> GetDistrict() {
        try
        {
            _databaseManager.ConnectToDatabase();
          return TransformDistrictBLLToDL(  _districtGateway.GetDistrict());

        }
        catch (SqlException sqlException)
        {
            Console.WriteLine(sqlException.Message);
            throw;
        }
        catch (FormatException formateException)
        {
            Console.WriteLine(formateException.Message);
            throw;
        }
        finally {
            _databaseManager.ConnectToDatabase();
        }
    }

    #endregion

Это код для бизнес-уровня.

Мои вопросы:

  1. Это идеальный дизайн?
  2. Если нет, то какие здесь недостатки?
  3. Я думаю, этот код с дублированным блоком try catch
  4. Что может быть хорошим дизайном для этой реализации

4 ответа

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

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

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

Теперь существует проблема курицы и яйца: вам нужно провести рефакторинг кода, чтобы протестировать его, но сейчас у вас нет тестов. Ответ заключается в том, чтобы начать с "защитных" методов рефакторинга и провести ручное тестирование. Вы можете найти более подробную информацию об этих методах в книге Майкла Фезера " Эффективная работа с устаревшим кодом". Если вам нужно провести рефакторинг большого количества унаследованного кода, вам действительно следует его прочитать. Это настоящее сенсационное сообщение.

На ваши вопросы:

  1. Там нет идеального дизайна. Есть только потенциально лучшие.
  2. Если в приложении нет юнит-тестов, то это самый большой недостаток. Сначала введите тесты. С другой стороны: эти фрагменты кода не так уж и плохи. Кажется, что DistrictDAO что-то вроде технической версии District, Возможно, была попытка ввести некоторую модель предметной области. И: по крайней мере DistrictGateway получает DatabaseManager вводится как параметр конструктора. Я видел хуже.
  3. Да, блоки try-catch можно рассматривать как дубликаты кода, но в этом нет ничего необычного. Вы можете попытаться сократить предложения catch с разумным выбором классов Exception. Или вы можете использовать делегатов или некоторые методы АОП, но это сделает код менее читабельным. Для получения дополнительной информации см. Этот другой вопрос.
  4. Поместите старый код в какой-нибудь тестовый комплект. Лучший дизайн неявно появится.

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

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

Отлично? Нет такой вещи. Если вам нужно спросить здесь, это, вероятно, неправильно. И даже если это "идеально" прямо сейчас, это не будет раз и энтропия завладеет им.

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

Дефекты? Сложно сказать. У меня нет энергии, времени или мотивации копать очень глубоко прямо сейчас.

Не могу понять, что вы подразумеваете под #3.

Типичное наслоение будет выглядеть так: стрелки показывают зависимости:

view <- controller -> service +-> model <- persistence  (service knows about persistence)

Есть сквозные проблемы для каждого слоя:

  • view знает о представлении, стилизации и локализации. Он делает все возможное, чтобы улучшить взаимодействие с пользователем, но не включает бизнес-правила.
  • Контроллер тесно связан с просмотром. Он заботится о связывании и проверке запросов из представления, маршрутизации к соответствующей службе, обработке ошибок и маршрутизации до следующего представления. Вот и все. Бизнес-логика принадлежит сервису, потому что вы хотите, чтобы она была одинаковой для Интернета, планшета, мобильного телефона и т. Д.
  • Сервис - это место, где живет бизнес-логика. Он беспокоится о проверке в соответствии с бизнес-правилами и сотрудничестве с уровнями модели и персистентности для выполнения сценариев использования. Он знает о вариантах использования, единицах работы и транзакциях.
  • Объекты модели могут быть объектами-значениями, если вы предпочитаете более функциональный стиль, или иметь более богатую бизнес-логику, если вы так склонны.
  • постоянство изолирует все взаимодействия с базой данных.

Вы можете рассматривать такие сквозные проблемы, как безопасность, транзакции, мониторинг, ведение журналов и т. Д., Как аспекты, если вы используете такую ​​среду, как Spring, которая включает аспектно-ориентированное программирование.

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

n-уровневая архитектура в последнее время кажется популярным вопросом, но это побудило меня написать серию блогов. Проверьте эти ТАК вопросы и сообщения в блоге. Я думаю, что они очень помогут вам.

Серия блогов по N-уровневой архитектуре (с примером кода)

Другие вопросы по тегам