Тег «функциональщина»

Domain Modeling Made Functional

Короткая книга от Pragmatic Programmers, в которой описывается как совместить Domain-Driven Design и функциональное программирование.

Ключевые моменты:

  • типизировать всё — плавно превращаем разговоры с доменными экспертами в строгие типы
  • выражать моменты типа «или заказ поступил по почте, или по телефону» через sum types (enum в Rust)
  • выражать моменты «заказ это список заказанных товаров И адрес доставки И подтверждение оплаты» через product types (struct и tuple в Rust).
  • выделять ядро домена, держать его «чистым»
  • выталкивать «инфраструктуру» (всё что не бизнес-логика) наружу из ядра домена (обращения к базам данных делать или до входа в ядро, или после, но не внутри)
  • моделировать воркфлоу как композицию функций, передающих друг другу Result по необходимости

В целом, книга тянет на серию хороших докладов по содержательности, и оказалась полезной для меня как раз примерами применения абстрактной теории (список выше) к более-менее правдоподобной системе. Более того, я извлёк несколько небольших полезностей, которые можно применять и в отдельности.

Так, например, можно заставить систему типов проверять куски нашей бизнес-логики. Скажем, айди товара — это строка из шести символов (A-E и пять цифр). Наивным решением будет использовать в коде просто String в местах, где нужен айди (я буду писать примеры на Rust):

fn get_product_by_id(id: String) -> Product {
  unimplemented!()
}

Но тогда мы теряем в выразительности. Можно сделать так:

type ProductId = String;

fn get_product_by_id(id: ProductId) -> Product {
  unimplemented!()
}

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

pub struct ProductId(String);
impl ProductId {
  fn from_string(s: String) -> Option<ProductId> {
    // check that s is correct identifier
    // return None if it is not
  }
}

…то остальной код не сможет создать значение типа ProductId не через функцию ProductId::from_string(s), которая всегда выполняет проверку строки на валидность.

У меня были схожие мысли до чтения книги, что статическая система типов может помогать избегать инъекций (различаем UntrustedString и TrustedString, и получить из первого второе можно только через функцию, которая делает проверки), но здесь авторы применяют это более широко.

Книга понравилась; мне кажется, что она зайдёт тем, кому любопытен DDD и/или применение функционального программирования в «жутком энтерпрайзе».