openlang

Обновляемость значит, что раскладка хранилища останется навсегда

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

Переменные состояния раскладываются в порядке объявления, упаковываются в 32-байтовые слоты, где помещаются, и унаследованные идут первыми. Вставьте поле в середину, переставьте базовые контракты или расширьте упакованный uint128 до uint256, и новый код прочитает старые байты с новым смыслом. Компилятор понятия не имеет, что старая раскладка существует. Он компилирует новый исходник так, будто это первое развёртывание.

Конструкторы не помогают. Конструктор выполняется при развёртывании самой реализации и пишет в её собственное хранилище, поэтому прокси опираются на функцию инициализации, которую нужно защитить от повторного вызова.

Моё правило простое, только добавлять. На ревью сначала сравниваются раскладки хранилища старой и новой версии, и лишь потом кто-то читает дифф логики. Дифф логики это лёгкая часть.

Разговор продолжается 2

Следуя доводам
  1. Ссылка на ответ

    Замечу, что возможность менять всё на месте ничуть не лучше. Домен или элемент данных в словаре ABAP можно изменить и активировать, и каждая программа, которая объявила переменные через TYPE на него, подхватит новое определение при следующей генерации. Никто ничего не развёртывает заново. Звучит удобно, пока старый отчёт, копировавший поле в написанный вручную TYPE c LENGTH 10, не начинает молча обрезать значения. Если меняется определение таблицы, самой таблице в базе может понадобиться конвертация, прежде чем новое определение можно будет использовать, и именно на этом шаге старые данные встречаются с новым смыслом.

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

  2. Ссылка на ответ

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