Куда мы помещаем код «спрашивая мир», когда отделяем вычисления от побочных эффектов?

10

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

Это оставляет без ответа вопрос: где относительно границы мы должны поставить «спрашивать мир»? С одной стороны, запрос данных из внешних систем (таких как база данных, API экстентальных сервисов и т. Д.) Не является прозрачным по ссылкам и, следовательно, не должен сочетаться с чисто вычислительным кодом и кодом для принятия решений. С другой стороны, проблематично или, возможно, невозможно отделить их от вычислительной части и передать в качестве аргумента, потому что мы можем заранее не знать, какие данные нам могут потребоваться.

Алексей
источник
1
Вот тут-то и вступают в действие концепции обратных вызовов. Если вы заранее не знаете, какие данные могут понадобиться, предоставьте обратный вызов вычислительному коду, где он может указать, какие данные ему нужны, и заставить другие уровни выполнять фактическую выборку и предоставление. , Если он должен быть асинхронным, обратный вызов может даже указать другую функцию для вызова с извлеченными данными, когда они станут доступны.
Марьян Венема
1
@MarjanVenema, это единственный вариант, который мне приходит в голову. Просто с теоретической точки зрения: если метод, без побочных эффектов, вызывает побочный обратный вызов, он становится побочным. Вероятно, моя проблема здесь в том, что я предполагаю, что вычисление отделения от побочных эффектов требует, чтобы вычисление было ссылочно прозрачным. Хотя это не обязательно правда.
Алексей
1
Если это ваше беспокойство, ваши вычисления просто недостаточно детализированы. Вы должны абстрагироваться от принятия решения о том, какие другие данные / шаги необходимы. Разделите все вычисления по шагам на основе того, где принимаются решения о том, какие данные нужны. Затем создайте своего рода «директора», который управляет рабочим процессом для полного вычисления: начиная каждый шаг, получая информацию от каждого шага, используя его для определения следующего шага и необходимых данных, запуская процесс извлечения для его получения и затем передавая извлеченные данные для следующего шага в вычислении.
Марьян Венема

Ответы:

1

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

Это случай, когда, как отмечено в комментариях, передача возможности извлечения данных (например, первоклассная функция, объект, который реализует интерфейс и т. Д.) Обеспечивает удобный механизм для выделения побочных эффектов.

Функция высшего порядка, чье тело чисто, имеет нефиксированную чистоту: http://books.google.com/books?id=Yb8azEfnDYgC&pg=PA143#v=onepage&q&f=false

Я писал об этом, называя этот тип функции потенциально чистой функцией: http://adamjonrichardson.com/2014/01/13/potentially-pure-functions/

Если вы комбинируете потенциально чистую функцию с сквозными функциями (в которых отсутствуют разветвленные конструкции и делают как можно меньше), комбинацию, которую я называю наборами изоляции, вы можете довольно эффективно изолировать побочные эффекты и создать очень тестируемый код: http: // adamjonrichardson.com/2014/01/15/isolating-side-effects-using-isolation-sets/

Адам
источник
0

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

class database_querier
    feature -- queries
        was_previous_query_ok : boolean is
            do
                Result = …
            end

        previous_query_result : string is 
            requires
                was_previous_query_ok
            do
                Result = query_result
            end

    feature -- commands
        query_db (…) is
            do
                …
                query_result = bla
            end

    feature {none} --data
        query_result : string
Ctrl-Alt-Делор
источник
1
Люблю видеть Эйфелеву в дикой природе.
ВОО
@sbi это просто псевдокод. :-)
ctrl-alt-delor
Достаточно близко, чтобы сделать меня счастливым;)
ВОО