Кратко

  • Parnas сопоставил разбиение по этапам обработки и разбиение по решениям, которые могут измениться. Оба варианта могли использовать одинаковые алгоритмы и даже дать одинаковое исполняемое представление.
  • Отказ хранить все строки в памяти или изменение упаковки символов затрагивали все модули первого варианта, но только Line Storage во втором. Смена представления сдвигов затрагивала три модуля против одного.
  • Information hiding ограничивает круг тех, кому необходимо знать решение. Это не секретность, шифрование, изоляция во время исполнения или синоним объектного подхода; интерфейс тоже способен раскрыть лишнее.

Архитектурный тест начинается после приёмки

KWIC означает Key Word in Context. H. P. Luhn в 1960 году опубликовал метод машинного построения указателя, где ключевое слово показывалось в контексте заголовка. Parnas взял небольшую версию уже известной задачи: прочитать строки, построить их циклические сдвиги, упорядочить их и вывести.

Статья 1972 года прямо говорит: работают оба решения. Они могут разделять алгоритмы и структуры данных, а после сборки быть одинаковыми для машины. Отличие находится в представлениях, которыми люди пользуются для изменения, документирования и понимания системы.

Поэтому современная иллюстрация сначала должна зафиксировать одинаковый результат. Затем следует заменить одно решение и посчитать, каким модулям, тестам и владельцам придётся менять своё понимание. Это способ объяснить аргумент, а не утверждение о том, что Parnas использовал современный тестовый стенд.

Первый разрез повторял ход обработки

Традиционная схема включала Input, Circular Shift, Alphabetizing, Output и Master Control. Работы были названы отдельно, но через границы проходили форматы памяти, общие массивы, индексы, указатели и соглашения о вызовах. Input упаковывал четыре символа в машинное слово; следующие этапы знали форму таблиц, созданных предыдущими.

Поток управления был разделён, а знание об изменяемом представлении — распределено.

Во втором варианте Line Storage владел внутренним представлением строк и давал операции для символов, слов и строк. Circular Shifter показывал клиенту множество сдвинутых строк, не раскрывая, хранятся они целиком, задаются индексом или вычисляются по запросу. Alphabetizer владел стратегией сортировки. Input и Output пользовались этими услугами.

Слово module означало назначенную ответственность, а не subroutine. Один модуль мог содержать несколько процедур; итоговый код мог объединять вклад разных модулей. Класс, пакет, процесс или команда могут реализовать такую границу, но не становятся ею автоматически.

Пять изменений показали распространение знания

Изменение входного формата оставалось внутри Input в обеих схемах. Традиционный вариант не проигрывал по каждой строке сравнения.

Если все строки больше нельзя было держать в основной памяти, в первом варианте менялся каждый модуль: каждый использовал общий формат. Во втором это решение знал только Line Storage. Так же распределялась замена упаковки четырёх символов в слово.

Переход от индекса сдвигов к полному хранению строк или к вычислению по запросу затрагивал Circular Shift, Alphabetizer и Output в первой схеме. Во второй он оставался внутри Circular Shifter.

Можно было и отказаться от однократной полной сортировки: искать очередной элемент при необходимости или распределить работу во времени. Первый Output ожидал готовый индекс. Во второй схеме клиенты не могли определить, когда именно Alphabetizer выполнял сортировку.

Информация не исчезает. У неё появляется один владелец, а остальные перестают строить код на этом решении.

Интерфейс тоже может сказать лишнее

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

Автор назвал это ошибкой проектирования. Способ вычисления был скрыт, но случайный порядок стал публичным. Закрытые поля и методы доступа не решают задачу, если формы возврата, порядок перечисления, временные гарантии или классификация ошибок повторяют внутреннее устройство.

Не секрет и не бесплатная оптимизация

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

Это не другое название объектно-ориентированного программирования. Абстрактный тип данных, класс и инкапсуляция могут помочь, а могут раскрыть формат хранения или нестабильную классификацию. Cohesion и coupling — полезный более поздний словарь, но он не заменяет названия скрываемого решения.

Зависимость сборки тоже не равна зависимости знания. Клиент может пересобраться без изменения исходного кода. И наоборот, независимо развёртываемые сервисы могут опираться на общий неописанный порядок.

Производительность не гарантируется. Parnas предупреждал, что частые сложные вызовы процедур могут замедлить второй вариант, и рассматривал вставку кода или специализированную передачу управления. Хорошая граница знания не отменяет инженерии исполнения.

Канонический пример тоже оказался неполным

Позднее Parnas отметил, что его KWIC всё ещё позволял каждому модулю знать: строка является последовательностью символов. Это общее предположение мешало представить часто используемые строки компактными целыми числами. Даже знаменитый пример не нашёл все решения, которые следовало скрыть, с первой попытки.

Развитие идеи было коллективным. Работа 1971 года описывала связи как предположения модулей друг о друге. В 1976 году программа семей расширила горизонт до родственных версий. В 1985 году Parnas, Paul C. Clements и David M. Weiss совместно различили модульную структуру, структуру uses и структуру процессов и предложили руководство по модулям для сопровождения.

Позднейшие исследователи снова использовали KWIC для сравнения общих данных, каналов и фильтров, событий и других стилей. Их выводы нельзя приписывать тексту 1972 года задним числом. Но его метод остаётся: удержать наблюдаемое поведение, изменить решение и проследить, как далеко распространяется необходимость знать.

Источники