Труба сквозь несущую стену

   
   
 

как не допустить выход канализации на потолке в кухне

Примерно 10 лет назад я решил что хочу построить себе дом. Не покупать готовый - чаще всего “дома на продажу” строятся скажем так очень топорно и с нарушением норм. А я все же инженер и посчитал что смогу разобраться и все проконтроллировать (спойлер - все получилось, но нервов потребовало достаточно). В итоге два года изучал матчасть - читал профильные форумы, разбирал СНиПы и т.д. Но так как я хоть и инженер, но по другому профилю, решил доверится профессионалам и купил готовые проект со всеми нужными частями: архитектурной, конструктивной, инженеркой. Предложение отличное - все есть, все продумано, бери и строй. Но, будучи control freak’ом, я решил все досконально проверить и воссоздать виртуальный проект дома в новомодном BIM (чуть ниже расскажу что это за зверь). Засучил рукава и взялся за дело.

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

Но по-настоящему меня добила не вентиляция. Меня добила канализация. Дело в том, что архитектор заложил санузел на втором этаже над гостинной, что в целом конечно ок для двухэтажного дома, но при сборке дома целиком оказалось, что канализационные трубы из него выходят на потолок кухни - а это уже мягко говоря негигеенично. То есть буквально: труба со второго этажа, по которой течёт то, что течёт по канализации, планово выводилась на потолок кухни. Той самой кухни, которая у меня смотрит на полуденное солнце.

И вот что здесь важно, ради чего я вообще это рассказываю. Ни один из проектировщиков не ошибся. Каждый раздел проекта — архитектурный, конструктивный, водопроводный — был внутри себя абсолютно корректен. Архитектор нарисовал правильные комнаты. Инженер провёл правильные трубы. Конструктор посчитал правильные стены. Ошибка родилась не внутри раздела, а на стыке разделов — там, где правильное встречается с правильным и вместе даёт нелепость. Каждый смотрел в свой чертёж и видел там порядок. Никто не смотрел в единую картину, потому что единой картины попросту не было — были отдельные чертежи, лежащие рядом. И именно для того, чтобы этой беды не было, строительная отрасль придумала целую дисциплину. Она называется BIM.

Что такое BIM

Чтобы объяснить, что такое BIM, надо сначала честно посмотреть, из чего вообще состоит проект здания. А состоит он из разделов — по числу инженерных дисциплин, каждая из которых отвечает за свою сторону дома.

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

Каждый раздел ведёт свой специалист, и каждый рисует свой комплект чертежей. А теперь вопрос: как эти разделы согласовать между собой? Как убедиться, что труба ВК не пересечётся с балкой конструктива, а воздуховод ОВК не упрётся в несущую стену?

До BIM это делалось руками. В буквальном смысле руками. Разделы велись как отдельные комплекты чертежей, и координация между ними держалась на глазе главного инженера проекта - ГИПа. Он брал чертежи разных разделов и сверял их между собой — иногда буквально накладывая одну кальку на другую на просвет и высматривая, не пересекается ли где труба с балкой. Это была честная, тяжёлая, внимательная работа — и абсолютно негарантированная. Стоило ГИПу устать, отвлечься, не наложить нужную пару калек — и коллизия проскакивала в стройку. Ровно так труба и оказывалась в несущей стене: не потому что кто-то ошибся в расчёте, а потому что человеческий глаз не в силах одновременно удержать шесть разделов сразу. А монтажники учились материться…

flowchart TD subgraph AFTER["После: единая модель"] M["Единая модель здания"] --> P1["План этажа"] M --> P2["Разрез, фасад"] M --> P3["Схемы разделов"] end subgraph BEFORE["До: разрозненные комплекты"] D1["Чертежи архитектуры"] --> EYE["Глаз ГИПа (калька на просвет)"] D2["Чертежи конструктива"] --> EYE D3["Чертежи ВК и ОВК"] --> EYE EYE --> RISK["Коллизия проскакивает в стройку"] end

До BIM разделы велись отдельными комплектами, а координация держалась на глазе ГИПа — и коллизия могла проскочить. После — все виды рождаются из одной модели, и расходиться им попросту неоткуда.

BIM возник как ответ на эту боль. И вот тут я обязан сразу разбить самое частое заблуждение, потому что без этого весь дальнейший разговор рассыплется. Многие думают, что BIM — это когда чертят в 3D вместо 2D. Красивые объёмные картинки вместо плоских планов. Это неправда, точнее — это самая поверхностная и наименее важная часть.

Суть BIM совсем в другом. Суть в том, что есть единая информационная модель здания, одна на все разделы, и из неё чертёж получается как проекция. Не наоборот — не «нарисовали планы, потом собрали из них модель», а именно из модели рождается любой нужный вид: план этажа, разрез, фасад, схема отдельного раздела. Все они — проекции одной и той же модели, взятой под разными углами. И второе, ещё более важное: элементы этой модели несут информацию, а не являются геометрическими примитивами. В обычном чертеже труба — это две линии, отрезки на бумаге, и всё, что о них известно, — их координаты. В модели BIM труба — это труба: она знает свой диаметр, свой материал, свой уклон, знает, что она — часть системы ВК. Она не нарисована, она описана. Отсюда и буква I в аббревиатуре — Information. BIM это не про три измерения вместо двух. BIM это про то, что в модели живут не линии, а осмысленные объекты, знающие о себе всё.

flowchart LR A["Архитектура"] --> M["Единая информационная модель здания"] K["Конструктив"] --> M VK["ВК"] --> M OVK["ОВК"] --> M EL["Электрика и слаботочка"] --> M M --> P1["План этажа"] M --> P2["Разрез, фасад"] M --> P3["Спецификации"] M --> P4["Сметы"]

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

Зачем нужна единая модель

Что нам даёт эта единая модель? Первое и самое очевидное — поиск коллизий прямо в модели, до стройки. Раз труба знает свой объём в пространстве, а балка знает свой, то их пересечение — это простой вопрос геометрии, который считает машина. Не глаз уставшего ГИПа, не наложение калек на просвет, а алгоритм, который берёт все элементы всех разделов и честно проверяет: не занимают ли двое из них одну и ту же точку пространства. Труба сквозь несущую стену, стояк над кухней — всё это модель ловит заранее, показывает красным и говорит: вот здесь конфликт, разберитесь.

И вот тут прячется мысль, которую я считаю ключевой не только для строек, но и для чего угодно вообще. Чем раньше ты ловишь ошибку, тем дешевле она обходится, и разница тут не в разы, а на порядки. Коллизия, пойманная в модели, — это пара кликов и десять минут работы инженера. Та же коллизия, пойманная на стройке, — это уже перекладка труб, переделка перекрытий, простой бригады. Я всем привожу пример - подвинуть стенку в модели - три секунды, подвинут стенку после залития бетоном - работа ребят с перфоратором. А та же коллизия, обнаруженная жильцом, когда он въехал и с потолка кухни закапало, — это катастрофа, суд и переделка всего. Одна и та же ошибка стоит копейки, тысячи или миллионы — в зависимости только от того, на каком этапе её поймали. Единая модель сдвигает поимку ошибки максимально влево, к самому началу, и этим экономит целое состояние.

Второе, что даёт единая модель, — связность видов. Раз все чертежи это проекции одной модели, то изменение в одном виде мгновенно расходится по всем остальным. Подвинул стену на плане — она подвинулась и на разрезе, и на фасаде, и в спецификации. Не надо руками синхронизировать десяток чертежей, надеясь ничего не забыть; модель одна, и правка в ней автоматически становится правкой везде. Расхождение между видами становится попросту невозможным — не потому что за ним следят, а потому что видам неоткуда разойтись, они все смотрят на один источник.

А дальше модель начинает обрастать новыми гранями, выходящими за пределы геометрии. Добавляют время — и говорят о 4D: модель знает не только где стоит элемент, но и когда он монтируется, то есть в неё встроен график стройки. Добавляют стоимость — и говорят о 5D: каждый элемент знает свою цену, и модель сама считает смету. Я не буду сейчас в это углубляться, для нашего разговора важно только одно: модель — не застывшая геометрия, а нечто, к чему прирастают всё новые и новые грани. Начиналось с формы, добавилось время, добавились деньги. Модель — это то, что накапливает грани.

Решатель

И вот теперь я хочу ввести понятие, ради которого, по большому счёту, вся эта статья и затевалась. Понятие центральное, и я буду возвращаться к нему до самого конца.

Всё, что я описал выше про поиск коллизий, делает не человек. Это делает отдельная штука, которую я буду называть решателем. Решатель — это не редактор, в котором рисуют модель, и не визуализатор, который показывает красивые картинки. Решатель — это вычислитель и проверяльщик целостности модели. Его единственная работа — взять модель целиком и ответить на вопрос: непротиворечива ли она? Нет ли в ней элементов, которые конфликтуют друг с другом? Не занимают ли двое одну точку, не нарушен ли норматив, не висит ли труба в воздухе? Решатель не создаёт и не украшает — он проверяет. В мире BIM роль решателя играют сами платформы: в Revit проверки целостности встроены в редактор, а Navisworks специально заточен на сведение разделов и поиск коллизий между ними.

flowchart LR M["Модель здания"] --> S["Решатель (проверяльщик целостности)"] R["Нормативы и правила"] --> S S --> V1["Непротиворечива: коллизий нет"] S --> V2["Список коллизий: труба сквозь стену, стояк над кухней"]

Решатель — не редактор и не визуализатор. Он берёт модель и правила и выдаёт детерминированный вердикт: либо доказанная непротиворечивость, либо точный список коллизий.

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

Поворот к софту

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

Смотрите сами. Есть PRD и ТЗ — описание того, что мы вообще строим, требования к продукту. Это архитектура нашего дома — то, как он устроен для пользователя. Есть ADR — записанные архитектурные решения, почему выбрано так, а не иначе. Есть дизайн и UX — то, как продукт выглядит и как в нём устроено взаимодействие. Есть код — несущий конструктив, то, на чём всё держится. Есть тест-кейсы — описания того, что и как проверяется. Есть автотесты — их машинная реализация. Есть документация. Есть инфраструктура — то, на чём всё это живёт и работает. Каждый из этих артефактов ведёт свой человек или своя роль, и каждый по-своему прав внутри себя.

И у софта — ровно та же болезнь, что у дома до BIM. Разделы расходятся. Дизайн говорит одно, код делает другое, тесты проверяют третье. Требования описывают продукт, каким он был полгода назад, а с тех пор его переделали дважды и забыли обновить ТЗ. Документация врёт, потому что её никто не трогал с прошлого года. Каждый артефакт внутри себя, может, и корректен — но вместе они противоречат друг другу. И это ровно те же проблемы дома из моего пролога: по отдельности и первый этаж хорош, и второй хорош, а вместе труба выходит на потолок кухни. По отдельности и код хорош, и тесты хороши, а вместе — тесты зелёные, а продукт делает не то. Разделы правильные, стык — нет.

Что делают со зданием, когда разделы расходятся? Заводят единую модель, из которой все чертежи — проекции. И я предлагаю ровно ту же идею для софта. Назовём её по аналогии SIM — единая информационная модель софта, из которой все артефакты — это её виды. ТЗ, ADR, дизайн, код, тесты, документация — не самостоятельные документы, лежащие рядом и расходящиеся, а проекции одной модели, взятой под разными углами. Как план этажа и разрез — это один дом с двух сторон, так требование и код — это одна система с двух сторон.

flowchart LR SIM["Единая модель софта (SIM)"] --> V1["ТЗ и PRD"] SIM --> V2["ADR"] SIM --> V3["Дизайн и UX"] SIM --> V4["Код"] SIM --> V5["Тест-кейсы и автотесты"] SIM --> V6["Документация"]

ТЗ, ADR, дизайн, код, тесты и документация — не самостоятельные документы, лежащие рядом, а виды одной модели софта, взятой под разными углами.

И вот здесь я обязан поставить огромный, жирный, важнейший дисклеймер, без которого вся аналогия превращается в опасную глупость. Я не утверждаю поэлементного соответствия. Я не говорю, что каждому требованию отвечает ровно один класс, а каждому тест-кейсу — ровно одна функция, и что всё это можно связать стрелочками один в один. Это было бы ложью и вредной ложью. В софте такого соответствия нет и быть не может. Переносится не структура «элемент модели = элемент чертежа». Переносится один-единственный принцип: видов много, и ценность — не в самих видах, а в согласованности между ними. Не в том, что есть код, и есть тесты, и есть ТЗ. А в том, что они не противоречат друг другу, потому что выводятся из одного и того же. Вот это, и только это, я предлагаю забрать из BIM в софт. Всё остальное — детали, в которых аналогия неизбежно поедет, и это нормально.

Я придумал — потом нашёл

Здесь надо честно сделать паузу и признаться. Когда эта мысль про единую модель софта у меня сложилась, я, как водится, решил, что придумал нечто новое. А потом, как тоже водится, пошёл искать — и обнаружил, что об этом думали до меня, и думали основательно.

Ближе всего к моей интуиции оказался Orthographic Software Modeling Колина Аткинсона — там прямо про то, что артефакты софта суть ортогональные проекции одной подлежащей модели (Single Underlying Model), ровно как виды в черчении. В ту же сторону копают в Vitruvius из KIT — фреймворк для согласованного view-based развития систем. Забавно, что даже аббревиатура SIM оказалась занята: System Information Modelling (I&E Systems, 1994) — это, по сути, тот же BIM, но для физических инженерных систем. Рядом стоят и смежные направления: MBSE и SysML в системной инженерии, OSLC для связывания артефактов между инструментами, living documentation, да и сами ADR как способ не терять решения. То есть поле давно вспахано, и ничего принципиально нового в самой идее нет.

Так в чём же тогда новизна? А новизна не в идее. Идея стара. Новизна в том, что только сейчас появилась возможность её реализовать — по-настоящему, а не на бумаге. И вот почему появилась — об этом весь остаток статьи.

Почему у софта нет детерминированного решателя

Вернёмся к решателю. В BIM он детерминированный и умеет доказывать непротиворечивость. Естественный вопрос: почему нельзя сделать такой же для софта? Взять SIM, натравить на неё решатель, и пусть он доказывает, что код не противоречит ТЗ.

А нельзя. И причина глубокая, не техническая.

Модель здания описывает физический объект с вычислимыми свойствами. Труба имеет диаметр, координаты, объём — всё это числа, и противоречие между двумя элементами есть противоречие между числами, а его машина считает. Артефакты же софта — это материализация мыслей на естественном языке. Требование написано словами. ADR написан словами. Код, конечно, формален, но смысл, который он воплощает, — это опять же мысль, выраженная словами в голове разработчика.

Возьмём пару. Требование: «пользователь не может вывести больше денег, чем есть на счёте». И код, где проверка баланса стоит, но выполняется до того, как учтена комиссия за вывод. Противоречат ли они? Да. Но это противоречие смысла, а не вычисления. Чтобы его увидеть, надо понять, что значит «есть на счёте», сообразить, что комиссия — это тоже расход, и соотнести намерение автора требования с тем, что реально делает код. Никакое пересечение объёмов тут не поможет — здесь надо понимать значение слов.

flowchart TD subgraph DET["Решатель BIM"] G["Предмет: геометрия и нормативы"] --> GF["Формализуем"] GF --> GP["Детерминированный ответ: доказательство непротиворечивости"] end subgraph NON["Решатель софта"] M["Предмет: смысл на естественном языке"] --> MF["Не формализуется"] MF --> MP["Вероятностный ответ: обоснованное подозрение"] MP --> MV["Цикл проверки и человек в контуре"] end

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

«Но есть же формальные методы!» — скажет въедливый читатель. Есть. TLA+, Coq, доказательства свойств. Они работают, и работают прекрасно. Но у них есть цена: чтобы ими воспользоваться, надо сначала перевести мысль в формализм — а этот перевод дорог, требует редкой квалификации и сам по себе ненадёжен. Формализуя требование, ты можешь ошибиться в формализации ровно так же, как в самом требовании, и получить строгое доказательство неправильного утверждения. Мысль, переведённая в формулу, — это уже не совсем та мысль.

И это не гадание. За последние сорок лет было немало попыток формализовать разработку целиком: CASE-инструменты, MDA с его model-driven подходом, round-trip engineering, где код и модель должны были синхронизироваться автоматически. Все они, при всём уважении и при отдельных нишевых успехах, в широкую практику не вошли. И причина, я убеждён, одна и та же: предмет не формализуется. Софт — это застывшая мысль, а мысль не сводится к геометрии.

И тут я обязан сказать честно, где аналогия с домом ломается. Здание строят один раз. Спроектировали, проверили модель, построили — и всё, дом стоит. Софт же меняется непрерывно, каждый день, каждым коммитом. А это значит, что согласованность видов для софта — не разовая задача «проверили перед стройкой», а постоянная. Модель здания замирает в момент сдачи; модель софта живёт, дышит и расходится ровно потому, что её всё время трогают. Решатель здесь нужен не один раз, а всегда. Это важное различие, и я не хочу его замазывать красивой аналогией: дом строят, софт выращивают, и это меняет всё.

ИИ как недетерминированный решатель

А теперь — то, ради чего всё писалось. И я нарочно говорю в настоящем времени, потому что это не прогноз и не мечта, а то, что уже работает сегодня.

Смотрите, где мы застряли. Детерминированный решатель для софта невозможен, потому что противоречия в софте — это противоречия смысла, выраженного естественным языком, а естественный язык детерминированной машине недоступен. Но у нас теперь есть машина другого рода. LLM работает именно со смыслом на естественном языке — ровно с тем материалом, который недоступен решателю из BIM. И вот ключевой разворот в голове, который надо совершить: решатель не обязан быть детерминированным. Он обязан быть полезным, с некоторой гарантией должен решить задачу. BIM приучил нас, что решатель доказывает. Но доказательство — это роскошь формализуемого предмета. Там, где предмет не формализуется, мы отказываемся от доказательства в пользу пользы — и это честная сделка.

Что конкретно уже сегодня умеет такой недетерминированный решатель? Перечислю проверки, которые работают прямо сейчас, не в теории.

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

flowchart TD CH["Изменили одну грань (например, ТЗ)"] --> FIND["Решатель находит затронутые грани: код, тесты, документацию"] FIND --> DIV["Выявляет расхождения между видами"] DIV --> AC["Actor-critic: актор правит, критик перечитывает реальный артефакт"] AC -->|расхождения остались| DIV AC -->|расхождений нет| CONV["Сходимость: виды снова согласованы"]

Недетерминированный решатель за работой: меняется одна грань — находятся затронутые, вскрываются расхождения, actor-critic цикл сводит виды обратно к согласованности.

И вот что мне особенно дорого: зерно этого уже посеяно. Вся машинерия из моей первой статьи — это и есть заготовка недетерминированного решателя. Фиксация договорённостей в артефактах — это и есть построение той самой единой модели, накопление её видов. А actor-critic цикл — это и есть работа решателя: критик, который читает реальный артефакт и сверяет его с задачей, буквально проверяет одну грань модели на согласие с другой. Критик, читающий код и сверяющий его со спекой, — это решатель, ищущий коллизию между двумя видами. Я, оказывается, строил решатель, ещё не зная, что строю именно его.

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

Финал

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

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

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