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

Философия Deep описывает всё концепцией Link. Любой объект это Link, любое отношение это Link. У отношения всегда указаны from и to. У самостоятельного объекта from и to не указаны. Это также отличает Deep философию от графовых баз данных, там edge не может служить объектом отношений.

Что может меняться в зависимости от моделей данных?

  • Переименование полей.

  • Изменение отношений one to one/many

  • Добавление абстракций

  • Устаревание абстракций

Всегда можно попробовать залатать проблемы с обратной совместимости добавлением новых адаптеров и слоёв. Но эта борьба с симптомами лишь отложит последствия настоящей проблемы. С каждым изменением бизнес логики эффект луковицы будет только нарастать. И будет становиться больше абстракций которые переплетены друг с другом.

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

Deep.Case ставит целью победить этого врага. Модели данных могут развиваться вообще не приводя к рефакторингу. Как? Для того что бы объяснить, разберемся в причинах проблем.

Переименование полей

Архитектура может быть разная. Вы можете использовать GraphQL и генераторы схем, или сопоставлять API и абстракции данных через ORM/ODM самостоятельно, пробрасывая правила работы с таблицами кодом. У вас может быть функциональное API и REST API с сервера. Но, вероятно, в любом случае схема работы с этими API будет определена либо на уровне API, либо на уровне имен колонок в таблицах. Таким образом, мы компенсируем вынужденные изменения оплатой разработчиков на то, чтобы обновить базу данных, генераторы, резолверы и API. Проблема здесь - разделение реализации функционала и интеграции его в бизнес логику. Этот один слой абстракции помножается на пересечения условий бизнес логики и обстоятельства связей между колонками, в итоге делая цену каждой волны сильно зависимой от возраста проекта. Точно подсчитать фактор зависимости не удалось, но эта цена всегда оказывается кратно больше стоимости самой модификации полей и конечного изменившегося поведения в бизнес сценарии.

Здесь же приходится учитывать права доступа и любые иные бизнес правила. Это увеличивает цену таких волн рефакторинга кратно правилам бизнес логики. Deep.Case позволяет полностью забыть об этой проблеме!

Изменение отношений one to one/many

Как бы мы не тешили себя иллюзиями, что можем все предугадать, это очевидно не так. Любая, даже самая идеальная модель, будет меняться. То, что мы считали единственной связью, станет множественной. То, что мы считали множественной из одной таблицы, начнет ссылаться из нескольких. Модели, задуманные к применению в одних местах, становятся необходимы во многих прочих. Каждое такое изменение сегодня снова требует участия разработчика.

С Deep.Case данные делятся на:

  • связи используемые в качестве нодов (точек), отвечающих на вопрос ЧТО, как например: платеж, объем, потребность, момент, и любые иные

  • связи используемые в качестве отношений (связей), отвечающих на вопрос КАК СВЯЗАНО, как например: X хочет Y, W просмотрел Z, T владеет R, T отвечает на P

  • кастомные таблицы поставляемые моделями данных, доступные из линка соответствующего типа. Предназначение таких таблиц - обеспечить хранение кастомных, не ссылочных, данных которые удобнее описать в отдельной таблице.

Связи, описывающие отношения, изначально не ограничены системой, как one/many. На уровне модели могут быть описаны, и в дальнейшем изменены правила создания связей каждого типа.

Это значит, что для перехода от oneк many достаточно разрешить создавать несколько связей определенного типа.

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

Добавление новых уровней абстракций

Например, когда нужно создать новый способ связи и новые сущности. С Deep.Case больше не нужно проходить полный цикл изменения структуры данных, моделей ORM/ODM, или учитывать как код отражает требуемые абстракции, и его негибкость тормозят изменения бизнес логики. Для такого рода изменений больше не нужен backend developer. Достаточно создать новый тип связей и описать, при каких обстоятельствах в окружающем пространстве эта связь может создаваться и меняться. Она сразу станет доступна через единый GraphQL/REST API, никак не повредив старым абстракциям и связям, а значит зависимому от них коду.

Деприкейт старых уровней абстракций

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

Поддержите ассоциативные технологии

Мы создаем среду разработки (коробочную CE/EE версию и SaaS версию), позволяющую использовать ассоциативный подход для решения ваших бизнес задач, нуждающихся в хранении данных, с возможностью адаптации под любые изменения бизнеса. Мы создадим распределённую сеть серверных кластеров в едином ассоциативном пространстве, в том числе чтобы не думать о региональном законодательстве, создавая проект. Мы создаём культуру публикации повторно используемых моделей данных с их поведением.

Присоединяйтесь к нашему сообществу в Discord. Подпишитесь на ранний доступ в нашем Waitlist или поддержите нас на Patreon.

http://deep.foundation/

На нашем сайте можно найти ссылки на черновики будущих статей находящихся в разработке, ссылки на исходники кода, планы по project и product менеджменту и invest презентации.

Комментарии (36)


  1. lair
    04.09.2021 20:29
    +6

    Обычно под рефакторингом подразумевают реорганизацию кода из соображений необходимости использовать данные по-новому.

    "Обычно" под рефакторингом понимают то, что дано в определении:


    Refactoring is a disciplined technique for restructuring an existing body of code, altering its internal structure without changing its external behavior.

    "Необходимость использовать данные по-новому" противоречит "без изменения внешнего поведения". Поэтому все, что вы описываете — не рефакторинг.


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

    Нет, не дешево. Особенно это не дешево в UI.


    Она сразу станет доступна через единый GraphQL/REST API, никак не повредив старым абстракциям и связям, а значит зависимому от них коду.

    Это все прекрасно, но кто и как обеспечит трансляцию старых связей в новые и обратно все время, пока поддерживается обратная совместимость?


    1. nin-jin
      05.09.2021 11:03

      А какие там сложности в UI?


      1. lair
        05.09.2021 11:05

        Ну так, если исходить из "итерируемости каждого подмножества", то у вас на форме заказа будет не один покупатель, а [0...n]. Это больно проектировать.


        1. nin-jin
          05.09.2021 11:43

          А боль-то в чём? Обычный мультиселект везде будет.


          1. lair
            05.09.2021 11:50
            -1

            Покупатель на форме заказа — это не обязательно одно поле. Туда много всякой интересной информации подтягивается.


            И когда пользователь там вместо одного набора видит таблицу, у пользователя возникает разумный WTF: это вообще как? Что значит "много покупателей"? А звонить кому? А платит кто? А отменить кто может?


            А адреса доставки? Тоже много? А это как, если у нас заказ из ровно одного предмета?


            1. nin-jin
              05.09.2021 12:12
              -3

              И таким образом мы бесплатно получили фичу "покупка вскладчину". Платить может кто угодно, главное набрать нужную сумму. Звонить любому. Отменять может любой. Адрес выбирается по договорённости в зависимости от времени доставки и адреса отправки. Опа, ещё одна фича "доставка туда, где вы находитесь, а не туда, где вас в это время нет".


              1. lair
                05.09.2021 12:15
                +1

                И таким образом мы бесплатно получили фичу "покупка вскладчину".

                Нет, не получили. Для ее реализации еще надо много что сделать, кроме добавления множества покупателей.


                Звонить любому.

                … а он вообще не в курсе, что это, он только денег занес.


                Отменять может любой.

                Упс, нет, только организатор покупки.


                Адрес выбирается по договорённости в зависимости от времени доставки и адреса отправки.

                Ага, в этот момент у вас началась адская пляска со стоимостью доставки и налогами. Ой.


                Опа, ещё одна фича "доставка туда, где вы находитесь, а не туда, где вас в это время нет".

                Вот только это не бесплатная для разработки фича.


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


                1. nin-jin
                  05.09.2021 12:33

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


                  1. lair
                    05.09.2021 13:08
                    +1

                    … и при min=max=1 система должна себя вести, как обычная с одним покупателем. Прекрасная идея, да.


                    Только стоимость разработки этого не равна стоимости разработки системы, где покупатель всегда один. Надо нарисовать и заимплементить два UI, надо сделать разные формы отчетности, и так далее. Ничего невозможного, конечно же. Но не бесплатно, совсем.


                    1. nin-jin
                      05.09.2021 13:24
                      -3

                      Это делается 1 раз за пару часов на старте проекта и далее реиспользуется во всех формах.


                      1. lair
                        05.09.2021 13:30
                        -1

                        Нет, не делается. Даже банально по временным затратам это дольше, и переиспользуемость не такая высокая, как вам кажется.


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


                      1. nin-jin
                        05.09.2021 13:37
                        -3

                        В прямых руках всё в порядке с переиспользуемостью. Мне не кажется, я это не раз делал.


                      1. lair
                        05.09.2021 14:03

                        Я повторюсь, мне кажется, мы с вами говорим о разном объеме изначальной работы. Вы "не раз делали" такую работу для крупной ERP-системы (тысячи сущностей со разным поведением), по всему стеку (дизайн, UX, бизнес-процесс, отчеты)?


                  1. JustDont
                    05.09.2021 13:31
                    +3

                    "Обычная" максима по поводу размерности данных говорит нам о том, что мы должны оперировать максимум тремя возможными состояниями: 0, 1, и N. Три их — вот ровно потому, что способ обработки каждого — различен, и эта разница продолжается во все стороны, от кода до UI и прочего I/O. Написать код так, чтоб эти три состояния всегда были закатаны в одно [0...N] конечно же вполне возможно, и вы даже сэкономите чуть-чуть (реально чуть-чуть) строк, если у вас и вправду все три состояния востребованы. Но когда у вас востребовано только состояние 1, а вы пишете код под [0...N] — вы напишете очень много лишнего.


                    1. nin-jin
                      05.09.2021 13:42
                      -1

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


                      1. JustDont
                        05.09.2021 13:46

                        И что же именно вы пишете "один раз"? Компонент-таблицу, способную обработать мощность [0...N] входящих данных (таблиц) уже написали, надеюсь?


                      1. nin-jin
                        05.09.2021 13:52

                        В том числе. А в чём вы видите проблему с реализацией такой таблицы?


                      1. JustDont
                        05.09.2021 13:54

                        Как именно она выглядит?


                      1. nin-jin
                        05.09.2021 13:57

                        В каждой ячейке от 0 до N значений, очевидно.


                      1. JustDont
                        05.09.2021 14:03

                        А почему не таблица с возможностью выбора текущего индекса?


                      1. nin-jin
                        05.09.2021 14:31

                        Я не смог распарсить вашу фразу.


                      1. JustDont
                        05.09.2021 14:38

                        В этом, видимо, и вся проблема.
                        Потому что "таблица мощностью N" всегда распадается на компонент-итератор, и компонент-таблицу. И нет ни одной практической причины совмещать их в какой-то готовый для употребления пакет: все случаи использования подобных конструкций достаточно редки, и среди них нет явного лида и аутсайдеров (это вам не Файрфокс, который, как широко известно в узких кругах, "никто не использует").


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


                      1. nin-jin
                        05.09.2021 14:56
                        -1

                        Вы специально используете специфичную для вашего проекта терминологию, чтобы ваш собеседник не понял о чём вы говорите?

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


                      1. JustDont
                        05.09.2021 15:14

                        Нет никакой проблемы 1 раз реализовать каждый из этих вариантов

                        Конечно нет. Речь о том, что реализовывать их заранее, до появления необходимости — довольно бессмысленная деятельность. Вы вот реализовали один из вариантов, и считаете, что у вас есть универсальное решение. А оно совершенно не универсальное.


                        Ну и в пределе ваш тезис — это "нет никакой проблемы 1 раз написать весь нужный вам код". Да нет, есть в этом проблема, особенно если спуститься с архитектурных орбит на землю.


                        Вы специально используете специфичную для вашего проекта терминологию, чтобы ваш собеседник не понял о чём вы говорите?

                        Термины (в приложении к веб UI) "таблица", "компонент", "селектор", "список" — для вас являются чуждыми и непонятными?


                      1. nin-jin
                        05.09.2021 15:23

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

                        "компонент-итератор", "таблица мощностью N" - всё это не понятно что такое без пояснений.


                      1. JustDont
                        05.09.2021 15:30

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

                        Я в курсе этой вашей точки зрения, про "весьма ограниченное число вариантов". Её беда в том, что она не бьется с реальностью. Как вот недавно с браузерами было.


                        "компонент-итератор", "таблица мощностью N" — всё это не понятно что такое без пояснений.

                        Но… первое это самый банальный реакт, который все видели, не? HOC, который рендерит список (итерируясь по входным данным)?
                        А про второе тут вся ветка. "Таблица мощностью N" — N таблиц.


                      1. nin-jin
                        05.09.2021 15:54

                        Она прекрасно бьётся с реальностью. Для любого свойства обычно есть не более 5 осмысленных вариантов отображения, основные из которых: список, таблица, галерея. Если вы не согласны - можете привести ещё хотя бы 3.

                        Итерирование через НОС я ещё не встречал, да и смысла в этом не вижу. Речь я вёл про более высокоуровневые компоненты типа "Сущность", "Свойство" и тп.


                      1. lair
                        05.09.2021 14:04

                        Я ж не тупой 100500 форм руками реализовывать с кастомным дизайном для каждой из них.

                        А, это все объясняет.


                        Наши заказчики хотят формы с кастомным дизайном.


                      1. nin-jin
                        05.09.2021 14:33
                        -1

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


                      1. lair
                        05.09.2021 14:36

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

                        Вам, несомненно, виднее.


  1. mSnus
    04.09.2021 20:58
    +2

    Пока что совершенно непонятно, как это все будет в реальности. Если у вас есть реальный код, использующий эту технологии -- например, исходники этого вашего Shake, было бы интереснее.

    Или хотя бы куски кода, иллюстрирующие данную статью. Без них -- очень много обещаний, хороший замах, но что в результате получается -- вообще неясно.


    1. novoselov
      05.09.2021 10:27
      +3

      Прочитал, ощущение что окунулся в какие-то влажные мечты frontend разработчиков об избавлении от backend разработчиков. Путанный набор мыслей, никакой конкретики, не понятно позиционирование и целевая аудитория. Открыл discord, там рассуждение про проект Венера и всеобщее благо. Дальше можно не продолжать...


      1. IvanSGlazunov Автор
        05.09.2021 17:23
        +1

        Мы рассматривали как ЦА только бекендеров и фулстеков. Такое восприятие фронтендеров мы еще не видели... Это очень ценно. Спасибо. Кажется у нас есть теперь новая ЦА...


  1. derikn_mike
    05.09.2021 01:29

    да не описана самая большая проблема когда разделяешь при высокой нагрузки - это атомарность без транзакций и локов.

    Например Видео хранит теперь только кол-во лайков , а кто лайкнул в отдельной таблице (или бд).

    и теперь твой код превращается в две строки....


    1. IvanSGlazunov Автор
      05.09.2021 17:27
      +1

      У нас есть транзакции, локи. Об этом будет в следующих статьях.


      1. derikn_mike
        05.09.2021 19:43

        очень жду статью по данным ситуациям , спасибо!