Статьи

Частичные обновления в неизменном мире

Этот пост был вызван беседой с хорошим другом, который является опытным Java-разработчиком, делающим свои первые, предварительные шаги к тому, чтобы стать программистом Scala. В основном разговор шел следующим образом:

«… Неизменность кажется хорошей и как цель, к которой я должен стремиться. Как я могу получить это в моих объектах домена без необходимости предоставлять множество конструкторов для частичных обновлений? Это действительно так важно? Мне редко приходилось беспокоиться об этом в Java! »

Оба честных вопроса, на которые я постараюсь ответить в оставшейся части этого поста.
Я обнаружил, что первый запрос на создание объекта имеет какое-то отношение к четко определенным идиомам и лучшим практикам в Scala, а ответ размыт из-за множества методов создания новых экземпляров объектов в Scala. Сокращение, чтобы погнать, подходящее решение для этого сценария состоит в том, чтобы использовать параметры по умолчанию и именованные параметры (функция, которая была в Scala начиная с v2.8, но мигает, и вы, возможно, пропустили их). Ниже приведен пример кода, и этот подход [в основном] использует тот факт, что вызывающая сторона выпускает обновление экземпляра класса в соответствующем контексте. Это позволяет обновлять только те атрибуты, которые были явно названы и переданы функции. Это также поощряет свободный стиль построения, благодаря которому мутации и операции над доменным объектом могут быть объединены в цепочку для формирования конвейера преобразования.

01
02
03
04
05
06
07
08
09
10
11
case class Person(val firstName: String, val lastName: String, val age: Int, val email: String) {
 def update(firstName: String = firstName, lastName: String = lastName, age: Int = age, email: String = email) : Person = {
  Person(firstName, lastName, age, email)
 }
}
 
val seedPerson = Person('A', 'B', 1, '[email protected]')
println(seedPerson)
 
val updatedPerson = seedPerson update (age = 100, firstName = 'Z')
println(updatedPerson)

Обратите внимание, что это не единственный подход к выполнению частичных обновлений, поскольку аналогичные результаты также могут быть достигнуты с помощью отражения [хотя за счет поддержки статической проверки типов] или с помощью экстракторов [которые, вероятно, будут более многословными из-за отсутствие контекста] или даже использование молний, ​​переписывание деревьев или линз ! (в зависимости от глубины и графа объекта, который необходимо обновить, и от того, требуют ли требования обновления всех элементов графа объекта на основе соответствия регулярному выражению / шаблону).

Итак, к вопросу о том, нужны ли вам неизменные объекты данных. Я считаю это последующим вопросом к более широкой проблеме: хотите ли вы на самом деле или вам нужен параллелизм вообще. Возможно, на разных концах « корпоративного » спектра поддержка параллелизма не подходит. Например, в системах с низкой задержкой, в транзакционных системах (где выполнение обычно однопоточное, чтобы избежать затрат на переключение контекста) и в однопользовательских встроенных устройствах (где ресурсы и уровни взаимодействия ограничены) параллелизм исключается из-за нефункциональных требований. Кроме того, некоторые бизнес-модели не должны учитывать параллельное выполнение, например, сценарии «его является разделенным издателем » (где идемпотентность важна, но не параллелизм).

Сказав это, (и несколько тавтологически) проблемы параллелизма обычно являются проблемой, когда они являются проблемой. В зависимости от профиля и семантики программы, система может работать некоторое время, прежде чем возникнут какие-либо проблемы. Однако, когда вы сталкиваетесь с ошибкой параллелизма, например, когда Джон и миссис Х встречались в Харте с Хартом, это может быть убийством . В конечном счете, если вы хотите или хотите получить гарантии параллелизма для своего домена, неизменность является одним из вариантов, и использование стандартных и именованных параметров Scala устраняет большую часть типичной проблемы реализации. Трудно что-то сказать «нет» ни за что (что-то, что я неофициально назвал бы принципом Лореа ).

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

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

Счастливого взлома!

Ссылка: Частичные обновления в неизменном мире от нашего партнера JCG Кингсли Дэвиса в блоге Scalabound .