На пути к своему продукту. От заказной разработки к созданию своей платформы

Введение

Я — разработчик ASP.NET. У меня небольшая команда разработки. В этой статье я коснусь некоторых проблем заказной разработки и способа, как мы эти проблемы решаем, и как мы постепенно перешли к созданию своего продукта — веб-платформы с подходом, где во главе угла стоит SQL.

Ключевые проблемы заказной разработки в нашей практике

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

Долго

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

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

Много ошибок

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

В итоге это ведет все к ошибкам, долгой отладке и лишним нервам.

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

Дорого

Очень часто заказчик сравнивает заказную разработку с созданием аналогичного продукта на готовой системе — какой-либо CMS. При этом совершенно не учитывается гибкость и возможность дальнейшего развития.

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

Возрастает человеческий фактор

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

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

При этом подготовка одного программиста по полному стеку — довольно непростая история. И далеко не сразу вопросы производительности для него становятся актуальными.

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

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

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

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

Что нужно заказчику

Что хочет от нас заказчик?

Экономия средств

Один из главных факторов — это деньги. Он хочет сэкономить и понимать свои будущие расходы на развитие проекта.

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

Скорость внедрения новых возможностей

Скорость внедрения идет рука об руку с экономией. Все, что долго внедряется, и бюджета требует больше.

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

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

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

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

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

Кастомизация

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

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

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

Низкие риски смены поставщика

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

Качество итогового продукта

На этапе запуска заказчик ожидает, что продукт должен быть хорошо протестирован и не содержать ошибок. В теории — да. Но посмотрите на количество патчей готового продукта ОС Windows (возможно сравнение некорректное ввиду сложности и масштабов, но суть примерно та же).

Здесь важнее понимать итеративную природу проекта, и с понимаем относиться к ошибкам (нашли — исправили — работаем дальше).

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

Что может предложить разработчик: заказная разработка и готовый продукт

Что может предложить веб-разработчик такому заказчику?

По большому счету у него 2 варианта:

  • сделать свое типовое готовое решение под конкретную задачу (например, CRM) и продавать это решение заказчику (если оно удовлетворит его потребности в полной мере).
  • предложить услуги заказной разработки (продавать часы программистов).

Оба решения имеют свои достоинства и недостатки.

Готовое решение сложно в дальнейшем кастомизировать, а заказная разработка — это очень долго и дорого.

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

Разработчику в идеале хорошо бы сделать свой типовой продукт и продавать его всем желающим направо и налево. Но есть свои нюансы:

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

Как увязать готовые продукты и заказную разработку

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

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

В идеале решение виделось таким:

  • создать некую платформу, которая позволяет делать быстрые изменения по бизнес-логики без необходимости делать обновления кода сайта.
  • некий пул типовых компонентов, которыми можно управлять из SQL. SQL все знают, хранимые процедуры в целом имеют довольно хорошие возможности по описанию бизнес-логики (наверно, это для ООП программистов звучит дико).
  • максимально уменьшить стек разработки, чтобы разработчику не нужно было изучать 6-7 технологий для поддержки проекта. Меньше технологий — дешевле поддержка, быстрее обучение, более надежно работающее решение.
  • стандартизация элементов и подходов к разработке. Раньше была проблема — каждый разработчик чуть-чуть, но все же по-своему делал некоторые элементы. И по мере развития проекта это значительно усложняет поддержку кода. В идеале, система должна выглядеть таким образом, как будто ее писал один человек.
  • крайне важно оставить возможность глубокой кастомизации. Без этого чуть возможных покупателей платформы откажутся в силу недоступности той или иной возможности. Т.е. задача сделать так, чтобы можно было относительно простыми средствами развивать систему под себя, не опасаясь, что мы не сможем реализовать какую-то бизнес-функцию приложения.
  • возможность наращивать способности системы от проекта к проекту. Не в плане брать чужие наработки по бизнес-логике, а в плане шлифовки возможностей стандартных компонентов (появление опций, правка сложных багов и т.д.)
  • меньше людей на проекте. Чем больше требуется разработчиков, тем сложнее координация, тем больше требуется звонков, совещаний, пояснений по бизнес-логике. При увеличении количества качество кода будет падать. И не факт, что это как-то ускорит проект.

Как появилась идея платформы и в чем ее суть

Управление метриками через SQL

В нашей системе учета, которую мы сделали под свои нужды, был модуль Метрики.

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

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

Вложенные метрики
Вложенные метрики

Тут важный момент в том, что метрики создаются постепенно (сейчас их более 250 и большинство из них уже не актуальны). Таким образом, такой подход экономил кучу времени (в сравнении с тем, если бы это было сделано через код приложения, например, через LINQ, EF).

Первые компоненты платформы

Параллельно у нас был JS компонент Таблица, который позволял относительно быстро собрать таблицу управления некой сущностью (CRUD): настроили JSON, создали метод Контроллера, прописали методы в бизнес-логике и DAL и таблица готова.

Пришла идея повторить SQL-подход на таблицах:

  • на странице находится некая разметка компонента (сниппет).
  • JS отправляет запрос за настройками в базу (где в таблице БД хранится информация о настройках таблицы)
  • вызываем нужную хранимую процедуру (которая возвращает данные и дополнительные настройки)
  • визуализируем все это на странице
Компонент таблиц
Компонент таблиц

Именно это в будущем и легло в основу построения любого компонента платформы:

  • Любой компонент — это сниппет разметки.
  • Она трансформируется через вызов хранимых процедур в определенном формате в Таблицу, Форму или Дашборд и т.д.
  • Любое действие в системе — это вызов определенной хранимой процедуры, которая генерируется по процедуре-примеру. Каждая процедура имеет жесткий формат вывода, задающий настройки и данные по работе компонента (может быть от 1 до 10 select в одной процедуре).

Пока не было идеи создать полноценную платформу. Было большое желание максимально ускорить создание таблиц и уменьшить количество дурацких ошибок, размазанных по всему стеку. Вместо 3-4 часов тратить на это 30-40 минут.

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

В тот момент ключевой проблемой на пути к возможности создания платформы была работа форм. Изначально было обходное решение: давать платформу как проект доработки в виде solution на ASP.NET. Но в этом случае мы получали проблемы обновления и все недостатки заказной разработки на полном стеке.

На пути к своему продукту. От заказной разработки к созданию своей платформы

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

Начало работы на платформе

Параллельно мы делали и клиентские проекты уже на базе новой платформы.

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

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

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

Возникающие проблемы и решения

Две ключевые проблемы на этом этапе:

  • как сделать универсальное API при соблюдении подхода платформы
  • как вызывать такие действия как отправка SMS, очистка системного кеша из SQL процедур.

Для API мы сделали 2 подсистемы: входящие методы API и исходящие запросы к внешним API.

Входящие методы — это, по сути, метод контроллера, принимающий все запросы, и, по коду действия определяющий хранимую процедуру обработки. Эта процедура обрабатывает входные данные и выдает результат, который отдается запрашивающей стороне в JSON, XML или plain text.

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

Отправлять запросы можно по POST, GET, параметры можно передавать в теле, header или через url.

Управление API
Управление API

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

В итоге было принято решение внедрять концепцию Внешних действий: платформа ожидает от хранимых процедур некоторых дополнительных select, в которых передаются нужные команды, например, отправить СМС.

Таким образом, мы выполняем «в SQL» действия, которые на деле совершаются уже после выполнения хранимой процедуры.

В целом о подходе

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

Внутренний код платформы не меняется под проект, только SQL-код создается под конкретную бизнес-логику проекта. Это делает возможным обновление платформы без необходимости как-то объединять кастомные проектные доработки (частые изменения) с доработками по ядру (редкие изменения).

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

Мы создали дополнительные инструменты внутри платформы, упрощающие перенос частей проекта на другую базу в виде SQL скриптов.

Постепенно создаем свои типовые решения и предлагаем их внедрение в рабочие проекты (например, компонент Блог или База знаний).

Кое-что пришлось оставить за бортом. Например, сильную нетиповую кастомизацию внутренних страниц в плане дизайна.

Лендинги в системе могут быть любые (они сделаны так, что код лендинга просто добавляется целиком и адаптируется в платформе).

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

Примеры дашбордов (панели показателей)
Примеры дашбордов (панели показателей)

Сильно кастомные проекты на внешний вид — это не про нас. Мы даем большую гибкость в плане изменения бизнес-логики и хороший внешний вид по умолчанию.

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

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

В общем, мы пожертвовали некоторой гибкостью в отношении дизайна, но оставили возможность изменений через CSS и JS.

При этом центральная рабочая область может быть сверстана как угодно. Компонент Форма позволяет использовать расположение элементы по умолчанию, но также позволяет внедрить свою кастомную разметку на Bootstrap 4.

Кастом разметка для формы
Кастом разметка для формы

Для полного освоения системы нужно знать 2 технологии: MS SQL и Bootstrap 4. SQL обеспечивает нам пластичность бизнес-логики, а Bootstrap — гибкость вывода данных в интерфейсе (при этом можно обойтись по умолчанию и без него).

Почему мы выбрали SQL? Разработка своего языка — это сложно и непонятно зачем, да и разработчику придется осваивать новое для себя. По субъективному ощущению, большинство программистов в том или ином объеме знают SQL (ну как минимум, сталкивались с ним в ВУЗе).

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

SQL — средство извлечения данных из базы данных. Используя его как основу, мы как минимум снижаем возможные риски проблемы производительности (конечно, это не панацея, но гораздо лучше Lazy loading и неоптимизированных запросов в LINQ).

Также компоненты за один вызов хранимой процедуры возвращают сразу несколько select. Это также уменьшает время на обработку запросов, требуется открывать меньше соединений с БД.

Внутри не используется тяжеловесная ORM (например, Entity Framework, Linq2SQL). Все запросы написаны в SQL и оборачиваются в объекты через Dapper (что сравнимо по скорости обработки с DataReader).

Основная разработка ведется через кабинет администратора. Потенциально можно делать горячие правки и через телефон (интерфейс адаптивен под мобильные).

Управление настройками страницы
Управление настройками страницы

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

Как внедрение платформы сказалось на проектах

Мы уменьшили количество людей на проектах. Для проекта мы привлекаем не более 2-3 человек (а раньше было до 10 человек). Это упрощает контроль, уменьшает ненужные взаимодействия на проекте и снижает себестоимость выполнения работ.

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

Это одно из главных преимуществ развития своего продукта по сравнению с разработкой без своего — вы непрерывно улучшаете его качество попутно. Решение каждой системной проблемы не теряется, а интегрируется в продукт.

Чем меньше мест, где разработчик может допустить ошибку, тем быстрее можно найти эту ошибку. В нашем случае 90% ошибок — это неточности в SQL. Именно там в первую очередь нужно искать проблему. Это также влияет на время отладки решения и, в целом, на сроки этапа.

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

Дополнительным плюсом для нас стало более простое обучение новых разработчиков для платформы. Если человек знает SQL и что-то слышал о HTML, то в целом не будет особого труда обучить его работе на платформе. Раньше обучение полному стеку могло занять 3-6 месяцев. Сейчас, в целом, при плотном изучении и практике можно освоить основные возможности платформы за 1-2 недели.

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

Что изменилось с точки зрения заказчика

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

Стоимость изменений снизилась. Правки делает один человек, нет нужды задействовать сложный цикл обновлений бизнес-логики. Если заказчик сам владеет SQL, то какие-то элементы он сам может менять в системе.

Соответствие ожиданиям. Заказчик изначально видит демо и примеряет это на свой проект. Его ожидания по внешнему виду формируются на самой ранней стадии. И не возникает в будущем сильного расхождения между желаемым и действительным.

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

Развитие платформы

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

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

В данный момент мы прорабатываем пробы соединения с другими базами, т.е. чтобы можно было сделать обработку данных в платформе из «неродных» баз данных (PostgreSQL, MySQL, Oracle).

Также важное направление — это работа на Linux (в целом демостенды на Linux уже есть, но еще требуют проверки всех возможностей платформы). Сейчас в основном система используется на Win хостинге либо на VPS с Windows Server.

Ну и самое главное — это создание слоя бизнес-модулей. Т.е. это уже укрупненные блоки, ориентированные на бизнес-задачи — учет кадров, отчет БДДС, генерация счетов и другие компоненты, которые в итоге собираются в подсистемы.

Интерактивный отчет БДДС
Интерактивный отчет БДДС

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

Один из кабинетов на демо
Один из кабинетов на демо

Минусы нашего подхода

У данного решения можно выделить следующие минусы:

  • некоторые возможности лучше делать в бекенд языке, а не в SQL (пример — вычисление хеша MD5 для кириллицы в SQL Server).
  • все же есть ограничения: по функционалу (в плане интеграции, например, передача файлов по API) и где-то приходится искать компромиссные решения.
  • все же браузер — это не среда разработки (многие предпочитают работать в IDE, а не кабинете на сайте)
  • потенциально — могут возникнуть такие потребности, которые лучше решаются в C# нежели в SQL в плане оптимизации по CPU (в этом случае их нужно будет решать либо за счет внешнего сервиса, либо за счет внедрений в ядро нового внешнего действия, что нехорошо с точки зрения архитектуры в общем случае).
  • необдуманные правки из личного кабинета могут привести к ошибкам или нестабильности. Это возникающие риски — плата за скорость и легкость правок по бизнес-логике приложения.

Заключение

Мы пока в начале пути. Еще многое предстоит сделать.

Но уже можно с определенностью сказать, что у нас есть свой продукт, который мы постепенно шлифуем с каждым новым проектом или нашим типовым решением/демо.

Прошу вас дать обратную связь по подходу (может мы велосипед делаем, но зато СВОЙ велосипед), а также дать совет как можно улучшить данный подход в плане стабильности системы в режиме сопровождения системы (когда идут оперативные правки на ПРОД)

http://falcon.web-automation.ru/ — сайт платформы

https://falcon.web-automation.ru/tst-customers — демостенд примеров

https://falcon.web-automation.ru/docs — техническая документация по платформе

33
2 комментария

Комментарий недоступен

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