Стратифицированный дизайн. Часть № 2

Стратифицированный дизайн. Часть № 2 #

Презентация #

Презентацию по теме лекции можно открыть по ссылке.

Видео-запись: Rutube

Документация #

Задания #

Задания выполняются на языке JavaScript в стиле лекции. Для каждого решения приводите обоснование: какое свойство дизайна улучшается и почему выбранное место для кода лучше альтернатив. Справочник по используемым методам: Object, Array.

  1. Замена структуры данных за барьером. Корзина реализована массивом, ниже приведены функции барьера из абстракций:

    function add_item(cart, item) {
      return add_element_last(cart, item);
    }
    
    function remove_item_by_name(cart, name) {
      var index = indexOfItem(cart, name);
      if (index !== null)
        return removeItems(cart, index, 1);
      return cart;
    }
    
    function isInCart(cart, name) {
      return indexOfItem(cart, name) !== null;
    }
    
    function indexOfItem(cart, name) {
      for (var i = 0; i < cart.length; i++) {
        if (cart[i].name === name)
          return i;
      }
      return null;
    }
    
    function calc_total(cart) {
      var total = 0;
      for (var i = 0; i < cart.length; i++) {
        total += cart[i].price;
      }
      return total;
    }

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

  2. Поиск протечки в барьере. Команда маркетинга написала код, который работает с корзиной:

    function has_expensive_item(cart) {
      for (var i = 0; i < cart.length; i++) {
        if (cart[i].price > 100)
          return true;
      }
      return false;
    }
    
    function promo_applies(cart) {
      return indexOfItem(cart, "promo") !== null &&
        calc_total(cart) > 50;
    }

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

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

    // A: внутри барьера
    function getsWatchDiscount(cart) {
      var total = 0;
      var names = Object.keys(cart);
      for (var i = 0; i < names.length; i++) {
        total += cart[names[i]].price;
      }
      return total > 100 && Object.hasOwn(cart, "watch");
    }
    
    // B: над барьером
    function getsWatchDiscount(cart) {
      return calc_total(cart) > 100 && isInCart(cart, "watch");
    }
    
    // C: гибридный вариант
    function getsWatchDiscount(cart) {
      return calc_total(cart) > 100 && cart["watch"] !== undefined;
    }
  4. Действие в слое вычислений. Ниже приведён код корзины, в который встроена запись в журнал:

    function add_item(cart, item) {
      logAddToCart(global_user_id, item);
      return objectSet(cart, item.name, item);
    }
    
    function update_shipping_icons(cart) {
      var buttons = get_buy_buttons_dom();
      for (var i = 0; i < buttons.length; i++) {
        var item = buttons[i].item;
        var new_cart = add_item(cart, item);
        if (gets_free_shipping(new_cart))
          button.show_free_shipping_icon();
      }
    }

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

  5. Анализ графа вызовов. Дан фрагмент графа вызовов приложения интернет-магазина:

    checkout_handler        -> validate_order, calc_total, send_receipt
    validate_order          -> check_fields, check_stock
    check_stock             -> fetch_stock
    fetch_stock             -> HTTP-запрос
    calc_total              -> доступ к полям товара
    send_receipt            -> build_receipt, print_receipt, update_db
    build_receipt           -> доступ к полям заказа

    Ответьте на три вопроса с обоснованием:

    • в какую часть графа поместить новое правило расчёта скидки, которое меняется каждый месяц;
    • с каких функций начать написание тестов при ограниченном бюджете и что именно они покрывают;
    • какая функция наиболее пригодна к повторному использованию в другом приложении и почему.
  6. Оценка пользы барьера. Команда из трёх человек обсуждает выделение барьера из абстракций над таблицей тарифов. Известно, что:

    • структура данных тарифов менялась один раз за два года;
    • обращение к тарифам встречается в 40 местах;
    • кроме команды тарифы используют две другие команды через те же функции;
    • изменение поля тарифа требует правки кода в нескольких местах.

    Примените шаблон «удобные слои»: решите, стоит ли выделять барьер, какие последствия будет иметь это решение для трёх команд и по какому признаку следует понять, что дальше улучшать дизайн не нужно.

© A. M. Васильев, 2026, CC BY-SA 4.0, andrey@crafted.su