Skip to content

Прикладная функциональность против универсальной конструкции

Частой ошибкой в разработке систем является игнорирование явного функционального моделирования системы: документирование принципиальных схем, описаний взаимодействия подсистем, ответа на вопрос «как работает», «каким способом меняет состояние предметов метода». В электронике и электрике, а также работе с непрерывными/потоковыми производствами[1] (химические и энергетические предприятия) обычно принято рисовать такие принципиальные схемы (документируются чаще всего диаграммами), на которых явно обозначаются или функции/процессы, или ролевые/функциональные части/единицы системы, или даже и то и другое вместе.

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

Например, программисты думают о функциональности своих программ, но принципиальных/концептуальных схем их работы программисты почему-то не делают, они держат обрывки этих принципиальных схем исключительно в уме — и поэтому в этих схемах нельзя найти пробелы, ошибки, поговорить о функционировании их систем с коллегами. Это не значит, что функциональных/потоковых нотаций не существует, например, data flow diargam[2] и даже архитектуры потоков данных (dataflow)[3], лежащие в основе ставшего популярным так называемого «реактивного программирования» [4]/«обработки потоков»[5].

В исходном коде программ, тем не менее, эти «принципиальные схемы» с их потоками не видны: парадигма программирования чаще всего не предполагает выделенного показа функциональности частей программы, плюс эта функциональность существенно зашумлена деталями описания, достаточными для исполнения кода. В передовых кругах разработчиков софта это не так, и функциональные описания (чаще всего получаемые в рамках практики domain driven design, DDD[6]) документируются, но пока это ещё не общепринятая культура/практика, скорее приятное и редкое исключение из общей практики.

Этот взгляд на систему как некоторые потоки от входов к выходам — он оказывается важным и для предприятия как системы. Так, операционный менеджмент — это как раз функциональный (иногда говорят — логистический, «транспортный») взгляд на предприятие как потоки работ (workflow), потоки комплектующих и предметов поставки (ERP, enterprise resource planning работает именно с планированием этих потоков, если нет планирования потоков — то это не ERP в оригинальном его значении).

Неработа с функциональностью — типичная ошибка объединившихся в проекте инженеров и менеджеров. «Техпредприниматели» или корпоративные менеджеры беседуют с внешними проектными ролями/stakeholders и выясняют обычно их потребности, а вот концепцией использования, то есть основными сценариями использования целевой системы не занимается вообще никто — инженеры сразу переходят к концепции системы, которая ещё непонятно что должна делать (непонятна её функция в надсистеме). В том числе в сценарии использования входят, заметим, не только happy path, то есть поведение системы, когда всё идёт хорошо и нет неожиданностей.

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

Для этого инженер соединяет через типовые интерфейсы из самых ходовых и простых стандартов типовые конструктивные элементы в надежде, что через восемь итераций всё как-то само-собой с функциональностью утрясётся (будет ведь обратная связь от недовольных клиентов!), и проект в конечном итоге получится успешным. Но это неэлегантно, не lean: добавляется лишняя функциональность, система за счёт этого становится обычно дороже, изготавливается дольше, но нужной функциональности может в первых итерациях и не оказаться, первые итерации потребуют переделок/re-work, они не будут представлять MVP.

Заметим, что примерно так и срабатывает «испорченный телефон»: беседуют с клиентом одни люди (которые не обучены системной инженерии), они формулируют и жёстко фиксируют (не просто документируют, а именно что «замораживают») требования с их обязательностью (а не в форме гипотезы о том, что нужно клиенту от системы), а разрабатывают потом систему совсем другие люди (которые обучены, но контакта с клиентом у них нет — и концепция системы поэтому оказывается плоха, гипотезу проверить удаётся только после того, как предъявили клиенту уже готовую систему с ошибочным набором функций).

Ошибку отсутствия функциональных частей системы в концепции системы тоже легко найти: в концепции системы при такой ошибке нет отражения предметной области, для которой целевая система осуществляет сервис, нет предметов сервиса, проходящих какие-то состояния в ходе обработки. Сервис назван (уж как могут его назвать люди, занимающиеся целевой системой, а не надсистемой), а предметов метода в надсистеме (что выполняет модуль как подсистема в составе надсистемы) — нет.

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

Вот почувствуйте разницу:

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

Функциональные диаграммы будут содержать названия функциональных частей или функций, а конструктивные/модульные/продуктовые диаграммы, замаскированные под функциональные всё равно будут содержать названия самых общий сервисов, и указывать обычно не потоки и порты**, а стандартизованные интерфейсы как места/каналы оказания сервисов****.**

Объяснить программисту необходимость делать функциональные описания в составе концепции системы трудно, ибо он мыслит компонентами/модулями/продуктами/фреймворками/платформами, которые, по его мнению, абсолютно универсальны и поддержат «любую функцию**».** Любую-любую? Помним, что вы должны удваивать любой встречающийся в описаниях систем квантор всеобщности**—** «каждый», «всякий», «любой», «все» и т.д. и ставить после этого вопросительный знак, сомневаясь в этой всеобщности. Всеобщности, увы, не случится. Но разочарование будет не в начале проекта, а поближе к концу — когда окажется, что универсальных прикладных софтверных систем не бывает, так же, как и любых универсальных систем «железных», «человеческих», «социальных» и т.п.

Архитектуру (архитектурные решения, которые относятся прежде всего к делению на модули и организацию связи между модулями для поддержки приемлемых значений более-менее одинаковых для самых разных систем архитектурных характеристик) программист признаёт, а концепцию системы**—** нет, функциональная декомпозиция у него идёт крупноуровневая «в голове», а затем сразу в исходном коде, «рабочке»****, и это ошибка в методе работы**.**При этом важность архитектурной работы уже признаётся в крупных проектах, само понятие архитектуры претерпело существенные изменения (подробней в руководстве по системной инженерии) и работа архитектора ставится в оппозицию работе разработчика. Даже появляется новая терминология для компонент/модулей, отражающая архитектурные соображения: архитектурный кванткак автономно вводимый в эксплуатацию конструктив, внутри которого обеспечена высокая функциональная связность[7]. Дальше мы ожидаем, что из архитектуры больших корпоративных приложений эти рассуждения про то, как делить систему на конструктивы, в том числе архитектурные кванты — перейдут и в «железную» инженерию, и ещё много куда. Грубо говоря, автомобиль с прицепом имеет довольно много конструктивных частей, но вот автомобиль и прицеп тут будут архитектурными квантами, их будут вводить в эксплуатацию автономно.

Даже если отвлечься от архитектурной работы (выполняемой отдельной ролью архитектора по методам работы архитектора, а не разработчика, причём это работа над конструкцией, а не над функциональностью), у программистов-разработчиков обычно случается много ошибок как раз по линии учёта функциональности. Разработчики как бы действуют как «недоархитекторы», налегая на «универсальные модульные конструкции», но забывая детально разобраться с функциональностью — но за учёт функциональности в конечном итоге ответственны именно разработчики, а не архитекторы.

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

У нас стоит задача тонкого химического синтеза диметилфторидметилхлорпентилбензолтитана для задач фармацевтической промышленности. Известно, что его трудно синтезировать, и при синтезе получается много примесей, от которых потом люди умирают. Поэтому мы предложим аптекам такой чистый продукт, от которого люди не будут умирать, а маркетинг будет оригинальный: через уборщиц медицинских учреждений, которые будут подбрасывать наши буклеты врачам, а также задушевно беседовать с пациентами в очередях ко врачам. Для того, чтобы получить чистый диметилфторидметилхлорпентилбензолтитан, мы будем использовать четыре стальных реактора, соединённых трубами диаметром 56мм, последняя труба с тефлоновым покрытием. Второй реактор закажем внешним контракторам. Чистоту получающегося диметилфторидметилхлорпентилбензолтитана будем отслеживать при помощи независимой экспертной службы. Все четыре реактора должны будут пройти проверку на выдерживание давления в 156 атмосфер.

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

Теперь представим инженера-разработчика в техническом отделе, которому пришедшие к нему представители коммерческой службы (маркетологи, эккаунт-менеджеры) говорят, что ему нужно будет решить задачу химического синтеза, но непонятно ещё какую. И они когда-нибудь потом, но вот не прямо сейчас наймут химика, который всё уточнит. Инженер соглашается и берётся за дело: ему сразу понятно, что нужны будут реакторы и трубы. Реакторов непонятно сколько, ибо непонятно, сколько там в синтезе будет химических реакций. Поэтому лучше бы этих реакторов было побольше. Он выбирает цифру 4, как «не очень мало, но и ещё не очень дорого», догадывается, что в этом синтезе может быть хитрая эндотермическая реакция, но сам он для такой реакции реактор вряд ли спроектирует. Так что этот «хитрый реактор» он отдаёт проектировать внешним контракторам и честно об этом пишет. Хотя внешние контракторы уже спрашивали, что там с массами и температурой, ответ пока никто не может дать, поэтому контракт планируется без разговора о сценариях использования — но контракторы, разумеется, от заказа не отказываются они говорят, что «сделаю любой реактор». Слово «любой» никого не отпугивает, ибо нет химика, который бы сказал, что же будет в этом реакторе происходить. Есть только инженеры по железу, хорошо разбирающиеся в марках стали и сварке, и маркетологи, беседующие с врачами и фармацевтами. Итог работы инженер и выражает в вышеприведённом абзаце весьма и весьма абстрактное описание системы, которое вряд ли приведёт к успеху, почти все принятые впопыхах решения потом придётся принимать заново: нельзя обсуждение конструкции ставить перед обсуждением функциональности.

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

В проекте получения чистого диметилфторидметилхлорпентилбензолтитана химика пока нет, про химию разговор поддержать некому, равно как сообразить, как же эта химия влияет на примеси, а примеси на здоровье пациента. За разговорами про конструктивы реактор****ов и труб к этому моменту уже можно забыть, что сама ситуация про медицину**, потребности тут в здоровье пациента** (целевая система тут в пациенте: окружают её в момент работы живые ткани**, а реакторы и трубы****—** в системах создания**,** «сбоку» целевого системного разбиения**/окружения, в другом времени, во времени создания****)****.** Делать, конечно, приходится железную конструкцию «нашей системы», но работать-то нужно функциональной системе, которая должна выполнить свою функцию в графе создателей! Нужно протянуть строгую логическую цепочку от целевой системы (синтезируемого вещества) к нашей системе (из труб и реакторов) — через функциональное описание, то есть химические реакции, которые описывают функциональность целевой системы (как она себя ведёт в пациенте, время использования), и далее к ведущим к появлению вредных примесей отклонениям от режимов проведения реакций в реакторе (время создания). При этом предметная область функциональных (химических) рассмотрений времени эксплуатации — по факту клиентская, а итоговые конструктивные (труб и реакторов) рассмотрения — предметная область изготовителя-контрактора, времени создания. По сути дела, это рассуждение — даже не очень полный проход по системной мантре.

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

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

Сначала нужно разобраться с функционированием: что происходит в тот момент, когда система работает/функционирует (слово «функционирует» тут не случайно! Интересуют функции и функциональные части! Это предмет интереса тех ролей, которые отвечают за работу системы!), а не когда её собирают из размещаемых где-то конструктивных частей продуктов/модулей/изделий/платформ. Потом в порядке модульного синтеза всё равно нужно будет рассмотреть и конструктивные части, и размещения. Но это всё потом, а для начала нужно сделать качественную функциональную декомпозицию, функциональный/системный анализ.

Рассмотрение функционированиясначала, а конструкции потом**—** это важная часть системного мышления**: сначала нужно обсудить подробно, зачем эти конструкции** и как они будут работать, а уже потом рассматривать, из чего они будут собраны**.**

В современной инженерии, тем не менее, не принято делать функциональную декомпозицию сверху-вниз, ибо при этом очень тяжело преодолевать последствия тех решений, которые придётся менять, когда за дело примутся специалисты по предметной области той или иной функции. Поэтому принято обычно визионерам (эта роль чаще всего исполняется на должностях продукт-менеджеров) приходить с какими-то идеями о том, что и с каким приоритетом надо добавлять к сервисам/функциям системы в её окружении, а затем за дело берутся архитекторы, которые по-грубому прикидывают, какие конструктивы вероятнее всего могут поддержать в их взаимодействии эту функциональность — но не делают сами функциональную декомпозицию. Далее они приглашают для детального рассмотрения функциональности сразу на нижнем уровне функциональной декомпозиции людей из тех команд, которые занимаются отобранными ими модулями. И итерации идут уже с ними. Тем самым грубая функциональная декомпозиция и модульный синтез делаются архитекторами и визионерами (в лице продуктовых менеджеров) на верхних уровнях, а вот детальные рассмотрения сразу идут на нижнем уровне, силами людей, хорошо разбирающихся в предметных областях этих функций/методов/сервисов, знающих особенности предметов этих методов.

Конечно, эти рассуждения относятся к инженерии чего угодно, необязательно «железа» или софта. Например, можно рассмотреть применение этих рассуждений к танцам. Просто махание ногами и руками (с запасом! Побольше махов, и сами махи пошире!) никого не устроит. Каждый мах должен быть понятен, зачем — какая там выражается эмоция или сигнал ведения: что этим махом хотят сказать, что продемонстрировать, какой ожидают результат. Тогда и мах будет подобран соответствующий (резкий, плавный, объёмный или короткий, рукой или ногой — ровно под необходимую функцию, а не «стандартный с бесчисленными вариантами из-за параметризации»). Если вам не нужно делать для вашего танца мах прямой ногой к уху (да ещё «с запасом под любую хореографию, с которой вы можете встретиться», как делается при создании и развитии танцоров классического балета, это примерно десяток лет тренировок), то вы можете сэкономить много лет жизни. Менее универсальные махи «под функцию», с учётом предметной области конкретного танца, тренируются много быстрее. Универсальных танцоров, музыкантов, инженеров, менеджеров, учителей не бывает — поэтому сначала надо задаваться вопросом «что будем делать», и только потом готовить не только «вообще», но и специализировать подготовку для выполнения конкретной функции. Так, в системном фитнесе можно выделить 4 проекта, которыми он занимается[8]:

  • Проект-1: Обучение изготовлению тела — стажировка по системному фитнесу (1 месяц), создание «тренера::создателя себя»
  • Проект-2: Изготовление тела - регулярные/специальные занятия (самостажировка, 12 месяцев), эксплуатация тренера, создание заготовки «тело как универсальный модуль».
  • Проект-3: Использование тела — изучение спорта/танца/борьбы (6 месяцев), используется универсальный конструктив, продолжение работы сам-себе-тренера, создаётся прикладной конструктив, выполняющий функции в прикладной предметной области.
  • Проект-4: Отдельная задача в выбранном спорте (3 месяца), развитие прикладного конструктива сам-себе-тренером до новой потребной приоритетной функциональности (вплоть до того самого «мах прямой ногой к уху с запасом», хотя тут может и не хватить 3 месяцев, но уж точно это будут не 10 лет, минимум впятеро быстрее).

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

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

  • Проект-1: Обучение созданию у себя универсального мастерства системного мышления — освоение руководства по системному мышлению (1 месяц, объём как четыре пятых «Войны и мира», но одолеть можно, много запомнится и даже поймётся, но устойчиво удерживаться в памяти не будет. Это уровень квалификации специалиста-аналитика: «знаю материал, но использовать не получается, ибо скорости не хватает, много не замечаемых быстро ошибок, затраты на мышление оказываются больше выгод»). По факту это создание тренера по системному мышлению для самого себя, то же самое, что и в стажировке по системному фитнесу.
  • Проект-2: Изготовление сам-себе-тренером, полученном в предыдущем проекте, универсального своего мастерства системного мышления, достижение беглости — регулярные/специальные занятия («самостажировка», 12 месяцев, но на реальных проектах, а не на учебных упражнениях. Впрочем, учебных упражнений в нашем руководстве нет, всё только на рабочих проектах)
  • Проект-3: Использование системного мышления для изучения какой-то прикладной инженерии, менеджмента, каких-то других методов прикладной работы (3-6 месяцев каждая). В программе рабочего развития инженеров-менеджеров это освоение работы по руководствам системной инженерии, инженерии личности, системного менеджмента.
  • Проект-4: Отдельная задача инженерии-менеджмента (от нескольких минут до 3 месяцев, «подумать и сгенерировать альтернативы, выбрать лучший метод работы, спланировать ресурсы, перейти к действиям и выполнить план»).

Мыслить только про «универсальные в плане функций конструкции**»** нельзя**, универсальных конструкций не бывает****. Отсутствие мышления о** прикладной функциональности нужно как-то осознавать и исправлять. А это отсутствие мышления о прикладной функциональности заметно только в случае наличия системного мышления**—** оно позволяет заметить то, о чём вы забыли подумать**.**

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

Внимательно посмотрите на свой текущий проект: не пропущены ли в нём функциональные рассмотрения? Если пропущены, то помним: без специалистов предметной области (subjectmatterexpert) надсистемы, а потом и целевой системы, и её подсистем, и вашей системы (если она из систем создания**)** вам не разобраться. Общайтесь, общайтесь, общайтесь. Системные мыслители много общаются с проектными ролями, отвечающими за самы****е разные прикладные практики, для этого они имеют универсальное/трансдисциплинарное/фундаментальное системное мышление, но они знают, что его результаты всё равно надо довести до какой-то прикладной системной области**.**


  1. https://en.wikipedia.org/wiki/Continuous_production ↩︎

  2. https://en.wikipedia.org/wiki/Data-flow_diagram ↩︎

  3. https://en.wikipedia.org/wiki/Dataflow ↩︎

  4. https://en.wikipedia.org/wiki/Reactive_programming ↩︎

  5. https://en.wikipedia.org/wiki/Stream_processing ↩︎

  6. https://en.wikipedia.org/wiki/Domain-driven_design ↩︎

  7. https://www.oreilly.com/library/view/building-evolutionary-architectures/9781491986356/ch04.html ↩︎

  8. https://www.youtube.com/watch?v=k7oyl99mMSE&t=13020s ↩︎