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

Итак, дано: филиал крупной сети ресторанного бизнеса, специализирующейся на доставке заказов на дом.

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

Основные проблемы существующей системы можно сформулировать так:

  1. Отсутствие должного контроля за служащими на каждом этапе:
    • кроме поваров ни кто не знает текущую нагрузку на кухню, кроме курьеров – текущую нагрузку на них.
    • Не фиксируются опоздания (если курьер опоздал больше, чем на 15 минут – это большой не зачёт всей фирме).
    • Сложно спрогнозировать сколько в какой день нужно поваров, курьеров.
    • Постоянное забывание курьерами второго пакета, если заказ большой, пересорты на кухне/упаковке, и прочие отсюда вытекающие вещи.
  2. Ошибки в адресах доставки, из-за которых курьер не всегда понимает куда ехать: не правильное написание улиц, номера домов, которые физически отсутствуют и прочие проблемы из-за отсутствия контроля за корректностью этой информации.
  3. Отсутствия распределения заказов по кухням. Нагрузка на кухни должна быть примерно одинаковая. То есть каждый заказ должен распределяться по точкам исходя из загруженности и пробок. Это невозможно реализовать без реализации контроля из п.1.

Конечно, должна при этом быть полная поддержка кассы (приходники/расходники сдачи, оплаты налом, всякие технические рейсы например для закупки еды), смены — за каждый промежуток времени работы точки должен быть ответственный, который ведёт кассу, заказы, выполняет остальные важные действия. И прочие мелочи, которые здесь наверно перечислять не стоит. ТЗ большое.

Многие спросят: а как же логистика склада? Как же учёт испорченного товара, логика закупок и пр.? Это решили реализовывать на следующем этапе. Так же как и выгрузку расходников/приходников в 1с, проводку зарплат через неё же и так далее. То есть сначала реализация оперативного контроля, а потом учёта.

Почему нельзя было взять готовую реализацию и интегрировать в этот бизнес? На рынке таковой нет. Заказчик перед тем, как начинать со мной сотрудничать готов был заплатить немалую сумму денег за готовую систему доделанную под его нужды. Но такой не нашлось.
Так же особое пожелание заказчика было, что бы всё работало шустро. Его нынешняя система, облачная, еле ворочается в браузере на i3. А когда, при пиковых нагрузках, в среднем приходит 1 заказ в минуту, наблюдать несколько секундные лаги интерфейса – это реальная потеря клиентов, и, соответственно денег. Но система тоже должна была быть с единым сервером.

Итак, я взялся за проект.


Средством разработки был выбран Rad Studio. Студия по некоторым причинам не очень популярна, но в данном случае мне, во-первых, хотелось получить единый код на всех устройствах, так как я один и не могу себе позволить несколько раз прописать одну и ту же структуру данных в нескольких средах разработки, а потом при любом изменении править в 10 местах. А во-вторых, я на всех платформах получаю компилированное приложение, которое теоретически всегда должно работать быстро. Но прежде всего меня волновала скорость на рабочем месте оператора.

Первое, что понадобилось – это интеграция с существующей системой. Заказы из неё должны попадать в новую без какой-либо задержки. Небольшое использование сниффера показало, что их программа раз в минуту опрашивает сервер, и, если есть новый заказ, то печатает pdf. Через полдня была готова моя программа, которая полностью копировала протокол оригинальной (до байта, спасибо, что исходники компонент дельфи доступны и там можно легко поправить заголовок http не заморачиваясь с raw socket), но помимо печати на принтере парсила эти pdf и вычитывала оттуда заказ, загружая его в базу.

Есть такая чудесная программа pdftotext. Запускаем с параметрами
–enc UTF-8 –raw

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

Вторая проблема — это база адресов. Понятно, что надо скачать ФИАС, загрузить его в базу. Но во-первых, вся база не нужна, не нужны квартиры, устаревшие записи и т.д., да и по факту интересен не сам адрес, а координата, куда везти. Я решил выгружать лишь населённые пункты, улицы и дома. И в таблицу домов для каждого добавил поля записи координат. Но так как, мягко говоря, не все дома есть в ФИАС, пришлось добавить возможность ручного ввода дома (и улицы естественно на всякий случай) но в таком формате, что бы при последующих обновлениях базы можно было бы эту запись сопоставить, и привязать соответствующий GUID.
Для геокодирования я подключил яндекс. У нас в городе он сейчас лучший. Итак, адрес из PDF сначала разбираем на улицу, дом, этаж, квартиру и так далее, затем смотрим в базе, есть ли этот дом, смотрим координаты. Если координат нет, геокодируем, проверяя на ~30 км от центра города, так как некоторые точки оказываются на Дальнем Востоке или в Сибири, причём там вообще нет населённого пункта. С этим глюком Яндекса не разбирался.

Если нет такого адреса, то смотрим на предыдущие выгрузки. Вдруг такое сочетание «улица-дом» уже встречалось, тогда берём координаты оттуда. То есть если улица, например, написана в оригинальной базе с ошибкой, то достаточно её 1 раз исправить, а не в каждом новом заказе.
Отображались адреса с помощью яндекс-карт через api 1.1. Оно не требует ID разработчика для всех нужд, что мне были нужны. Правда было серьёзное ограничение у TWebBrowser (компонент, который отображает любую web страницу, в данном случае карту) в нём можно запустить любой скрипт из основной программы в нужный момент, но принять данные не возможно ни в какой форме. Однако, есть интересный хак — когда надо принять данные, в скрипте надо выполнить:

function ApplyPoint(){
var text = 'http://ya.ru/1.htm?&P&&';
text = text + '[' + placemark.getGeoPoint().getY();
text = text + ',' + placemark.getGeoPoint().getX()+']';
window.location = text;
};

А в дельфи:
Запускаем скрипт:

procedure CMapElement.ApplyEditPoint;
begin
   if not assigned(control) then
      exit;
{$IFDEF CLIENT_BUILD}
   (control as TTMSFMXWebBrowser).ExecuteJavascript('ApplyPoint();');
{$ENDIF}
end;

А затем:

procedure CMapElement.WebBrowser1DidFinishLoad(ASender: TObject);
var
   s,s2 : string;
   p : integer;
   co : ArrMapCoord;
begin
   if not assigned(control) then
      exit;
{$IFDEF CLIENT_BUILD}
{$IFDEF MSWINDOWS}
   s :=(control as TTMSFMXWebBrowser).FWebBrowser.GetRealURL;
{$ELSE}
   assert(false);
{$endif}
   if (pos('ya.ru', s) > 0) and not AlreadyReload then
   begin
      p := Pos('?&',s);
      delete(s,1,p+1);
      s2 := s;
      p := Pos('&&',s);
      delete(s,1,p+1);
      delete(s2,p,9999);
      if s2 = 'P' then         //Конец редактирования точки (таскания по карте)
      begin
         WeEditPoint := false;
         self.DecodePolyString(s,co);
         if Length(co) = 1 then
         begin
            AddressPoint.la := co[0].la;
            AddressPoint.lo := co[0].lo;
         end;
         AlreadyReload := true;
      end
      else
      if s2 = 'R' then      //Вычесленное расстояние маршрута
      begin
         WeCalcRoute := false;
         if Assigned(g_CurrentScriptRunner) then
         begin
            g_CurrentScriptRunner.OnExternalAction('MapRouteDist',s);
         end;
      end
      else
      if StrToInteger(s2,p) then
      begin
         Polys[p-1].Poly := s;
      end;
      AlreadyReload := true;
      LoadMap;
   end;
   MapLoaded := true;
{$ENDIF}
end;


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

Ну и это всё надо как-то увязать. Я хотел сделать не просто ERP систему под конкретного заказчика. Я хотел, что бы она была достаточно универсальной, настраивалась из конфигурационного файла, а вся логика и интерфейсы не были завязаны на сам исполняемый файл. Сейчас вся конфигурация содержится в одном xml файле. Этот файл со всей структурой базы, со всеми интерфейсами и скриптами считывается сервером, а затем выдаются нужные части клиентам.

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

Скриптовая система была написана с помощью Pascalc. Библиотеке более 15 лет, но она очень удачна: легковесна, легко расширяема и модифицируема под любые нужны. Поэтому включаем для следования стандарту паскаля на мобильных устройствах директиву компилятора
{$ZEROBASEDSTRINGS OFF}

Вносим несколько правок типа Destroy->Free, убираем использование win api и вот скрипты без проблем работают под любой ОС, а библиотека обработает подобный скрипт:

Пример скрипта
CurOrderState := GetNewValueF('Orders','OrderState');
LastOrderState := GetOldValueF('Orders','OrderState');
IsCashbackOnCurier := GetNewValue('Orders','CashbackOnDeliverer') = 'True';
PayType := GetNewValueF('Orders','PayType');
OldPayType := GetOldValueF('Orders','PayType');
OrderTurn := GetNewValueF('Orders','Turn');
CurTurn := GetConstantValue('CurrentTurn');
OrderNo := GetNewValue('Orders','OrderNo');
OrderPrice := GetNewValueF('Orders','Price');

PaySum := GetNewValueF('Orders','PaySum');
LastPaySum := GetOldValueF('Orders','PaySum');

CurTurn := GetConstantValue('CurrentTurn');
CurCashbox := GetConstantValue('CurrentCashbox');

if (OrderTurn > 0) and (OrderTurn <> CurTurn) then
begin
   ShowMessage('Нельзя производить действия с заказом другой смены. Заказ №'+IntToStr(OrderNo));
   exit;
end;

if (LastOrderState = 9) then
begin
   ShowMessage('Нельзя производить действия с завершенным заказом');
   exit;
end;

if (LastOrderState = 8) then
begin
   ShowMessage('Нельзя производить действия с отменённым заказом');
   exit;
end;

if (LastOrderState <> 8) and (CurOrderState = 8) then
begin
   TransactionCanAccept;
   exit;
end;

if (CurOrderState > 2) and (CurTurn  < 1) then
begin
   ShowMessage('Смена не открыта. Действие не может быть совершено');
   exit;
end;

if (CurOrderState > 4) and (CurCashbox  < 1) and (CurOrderState <> 8) then
begin
   ShowMessage('Касса не открыта. Действие не может быть совершено');
   exit;
end;

//Запрет изменения сумм, так как есть кассовые доки.
if IsCashbackOnCurier then
begin
   if PaySum <> LastPaySum then
   begin
      ShowMessage('Уже нельзя менять суммы оплаты');
      exit;
   end;
   Price := GetNewValueF('Orders','Price');
   LastPrice := GetOldValueF('Orders','Price');
   if Price <> LastPrice then
   begin
      ShowMessage('Уже нельзя менять суммы оплаты');
      exit;
   end;
end;

// Формируем сдачу
if (CurOrderState >= 6) and (CurOrderState < 8) and (PayType = 1) and (not IsCashbackOnCurier) then
begin
   if (PaySum - OrderPrice) > 0 then
   begin
      ss := 'Выдача сдачи для заказа №'+IntToStr(OrderNo);
      CreateCashboxDoc(ss,1,OrderPrice - PaySum);
      IsCashbackOnCurier := True;
      SetValue('Orders','CashbackOnDeliverer',True);
   end;
end;

//Отмена сдачи для курьера по статусу
if (CurOrderState < 6) and IsCashbackOnCurier then
begin
   if (PaySum - OrderPrice) > 0 then
   begin
      CreateCashboxDoc('Отмена выдачи сдачи для заказа №'+IntToStr(OrderNo),1,PaySum - OrderPrice);
      IsCashbackOnCurier := False;
      SetValue('Orders','CashbackOnDeliverer',False);
   end;
end;

// Формируем возврат сдачи
if (CurOrderState >= 8) and IsCashbackOnCurier then
begin
   if (PaySum - OrderPrice) > 0 then
   begin
      ss := 'Возврат сдачи для заказа №'+IntToStr(OrderNo);
      CreateCashboxDoc(ss,1,PaySum - OrderPrice);
      IsCashbackOnCurier := False;
      SetValue('Orders','CashbackOnDeliverer',False);
   end;
end;

// Формируем приходник на сумму заказа
if (CurOrderState = 9) and (LastOrderState <> 9) and (PayType = 1) then
begin
   ss := 'Розничная выручка с заказа №'+IntToStr(OrderNo);
   CreateCashboxDoc(ss,2,OrderPrice);
end;

// Назначаем смену и филиал при переходе из статуса новый дальше
if (LastOrderState < 3) and (CurOrderState >= 3) then
begin
   if CurTurn <= 0 then
   begin
      ShowMessage('Смена не открыта. Движение заказа не возможно.');
      exit;
   end;
   SetValue('Orders','Turn',CurTurn);
   CurFilial := GetConstantValue('FilialID');
   SetValue('Orders','Filial',CurFilial);
end;

if (CurOrderState <= 2) and (LastOrderState > 2) then
begin
   SetValue('Orders','Turn',0);
end;
TransactionCanAccept;


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

Следующий важный кейс – это программа оператора. Все данные находятся в облаке, необходимо их без задержек получать, генерировать изменения и так далее. Я решил уйти по максимуму от связи с сервером в реальном времени. Зачем по 100 раз тащить одну и ту же запись, если её можно закешировать в ОЗУ, и обращаться в любой момент?
Я выгружаю в память все актуальные заказы, клиентов, адреса и пр. То есть не таблицу целиком, что будет глупо, и память быстро закончится, а лишь ту часть таблицы, что необходима. Как кэш в процессоре. Если данные в нём есть, обратимся сразу, если нет, то придётся подождать, пока сервер отдаст их. Так же был прописан механизм “подписки на изменения” таблиц: если какая-то запись какой-то таблицы изменилась, всем подписчикам придёт об этом уведомление с новыми данными. В результате комфорт работы с приложением в плане латентности стал максимальным. Реакция на изменения фильтра, переупорядочивания, открытия заказа и пр – всё моментально.

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

Всё это было опробовано и заработало на одном филиале “в боевых” условиях. Не было ни каких нареканий. Точнее сначала была пара проблем с курьерским приложением – оно работало не очень отзывчиво, если интернет связь была плохая. Я дополнительно закешировал данные, провёл ряд оптимизаций, и всё стало работать без каких-либо лагов.

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

  1. Запуск “на холодную” курьерского приложения 4 секунды. Слишком долго.
  2. Надо менять язык программирования и полностью переписывать всё из-за п.1.

На этом мы расстались.

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

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


  1. Melex
    25.12.2017 23:45

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

    Идти в мир 1С, если нравится работа с такого рода задачами, и там, вы можете стать очень хорошим и востребованным профи.
    Так как типичные кодеры 1С в основном знают только 1С, и кричат что им этого достаточно и они гуру.
    Настоящие профи — знают более чем 1 язык программирования, а реальные профи — минимум 3-4. Да, может не на 100%, но это и не надо.
    У меня в 1С сейчас возникают схожие задачи, например, если контора, там есть торговые и курьеры, и служба доставки, и прочие прелести.
    Так вот, со времени внедрения мы задали клиенту всего один вопрос:
    «Как курьер решает — куда ехать в первую очередь?».
    Это все переросло в громадный проект, где:
    1. Гео позиции взятых заказов, с анализом того, заказ был взят около клиента, или хз где.
    2. Решение задач коммивояжера
    3. GPS трек в машинах
    4. Вывод карт с реальным и оптимальным маршрутом, рассчет себестоимости доставки вплоть до конкретного клиента (а это еще та задачка)
    5. Вывод и наложение маршрутов, с расчетом расстояния и простоев
    6. Служебные поездки и оптимизация ГСМ
    И куча куча всего другого.
    Тут пришлось кодить карты, причем иногда это Яндекс, иногда опенстрит, так как нужны графики пирогов по особому алгоритму, которые ни гугл, ни яндекс не дает делать нормально.
    Тут же мобильные прилоежения (в том числе на 1С), и службы сбора текущих координат (это уже нативное)
    Тут и вывод карт, сохранение скринов карт с анализом дальнейшим
    Тут же интеграция с гуглом, яндексом, свои приблуды, с GPS трекерами и т.д.
    И увы, большенству 1Сников такие задачи не поднять, в силу ограниченности знаний только 1С, и чаще всего не умением вкурить в английские мануалы, та и вообще в английский. А чаще всего — они даже не знают что так вообще можно.
    А вот вы, с вашим опытом и знанием, и уже даже пониманием предметной области, можете очень не хило зарабатывать тут, и заниматься чуть ли не сразу интересными проектами, начиная с того, что помогать 1Сникам в написании вот таких приблуд как я описал.
    Так как и 1Сникам не легко веб программисту объяснить многие тонкости учета бизнеса, и почему это надо именно так, большенство из них (веб программистов) думает, что это 1С такая тупая и не может по другому, а по факту — это требование бизнеса, и тут не выкрутиться.
    Плюс, 1С умеет в oData и rest full api, причем для работы с ними — не надо лицензии (если память не изменяет), так что если вы свою приблуду сделаете как сверхлегкий клиент, который будет только описывать интерфейс, то и тут тоже вам рынок будет.
    Короче — подумайте :)


    1. akadone Автор
      26.12.2017 23:45
      -1

      1c — это крутая штука, но, к сожалению, низко оплачиваемая. К тому-же придётся работать в офисе. В последние 10 лет я так не работал, и не хочу, если честно :)


      1. adm1nb3k
        27.12.2017 02:14

        Я думаю, что это не правильная мнение, не зная сферу 1С.


        1. akadone Автор
          27.12.2017 02:15

          Расскажите пожалуйста, как работая в сфере 1с заработать (работая на дядю ес-но) хотя бы $5000.


          1. Melex
            27.12.2017 17:55

            в месяц? Ну только при условии что язык подвешен. Тогда можно и больше, много больше.
            И при зп больше чем 3к в месяц, вы уже на дядю не захотите работать, а задумаетесь над тем, чтобы стать этим дядей :)


      1. Whuthering
        27.12.2017 11:19

        А скажите, эти 10 лет «не в офисе» вы работали в крупных командах с налаженными механизмами взаимодействия (типа обязательного code-review, автотестов, и т.д.), или пилили все в одиночку/парой человек, варясь в собственном соку?
        Если второе, то это многое объясняет, без обид.


  1. caballero
    26.12.2017 01:57

    а не надо было никакого курьерского приложения. Надо было создать веб интерфейс и было бы и кросплатформенно и в реалтайм и ничего не надо нигде кешировать. Проблемы с интернетом ща могут быть разве что в лесу далеко за городом. Да и вообще ERP в виде десктопа (хоть и сам писал раньше такое на старом добром делфи) — имхо вчерашний день.


  1. DrPass
    26.12.2017 03:57

    А в дельфе

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


  1. vism
    26.12.2017 11:56

    Ну чтож, повторюсь…
    Когда читал статью, был в шоке.
    Сам в основном занимаюсь разработкой ERP, CRM.

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

    ERP такая штука, которая всегда подвержена доработкам и изменениям, притом доработкам, порой очень нелогичным (которые не укладываются в логику).
    Такие системы должны быть:
    1. Очень гибкие — чтоб можно было менять и дорабатывать все что угодно, особо при этом не ломая другие модули
    2. Написаны на популярных и простых технологиях — если вдруг за такой код, как вы делали, вас в лес увезут, чтоб другой программист мог дальше работать. Ваш код легче выкинуть, чем копаться в ваших изобретениях.

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

    Средством разработки был выбран Rad Studio. Студия по некоторым причинам не очень популярна, но в данном случае мне, во-первых, хотелось получить единый код на всех устройствах, так как я один и не могу себе позволить несколько раз прописать одну и ту же структуру данных в нескольких средах разработки, а потом при любом изменении править в 10 местах. А во-вторых, я на всех платформах получаю компилированное приложение, которое теоретически всегда должно работать быстро. Но прежде всего меня волновала скорость на рабочем месте оператора.


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

    И код был бы единый, с константами, без хаков и главное Поддерживаемый!!! Это самое главное что нужно клиенту!
    Клиенту всегда нужно, чтоб бизнесс работал, а не ваши изобретения. Он всегда хочет знать, что если вы пропадете по любой причине, его бизнес не сдох из-за вашего выбора технологий. И что пару лямов он потратил не привязавшись только к вам как единственному, кто может апдейтить систему.
    Вы свинством занимаете, еще и продать теперь хотите кому-то.


    1. PallaDio
      26.12.2017 23:09

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


    1. akadone Автор
      27.12.2017 00:03

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

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

      А вот тут позвольте не согласиться. Можно нанять 1 человека за $1500, и 6-8 человек на $800, и они что-то будут делать годами. И любая серьёзная доработка — это тележенье заказчика минимум пол года (это сугубо из практики). А можно одного нормального программиста тысяч за 5, пару джуниуров в помощники тысячи по 1.5, и пару скриптовиков за те-же $600-800. Лид за короткое время допилит основную часть системы, и переключится на другую задачу, джуниоры будут допиливать расширения api, сборку проекта и пр. Ну а скриптовики будут как раз и удовлетворять все потребности заказчика. Чем не вариант? Он кстати дешевле, стабильнее и как-бы эффективнее.
      Только сделать это на вебе было бы очень даже не плохо и работало бы очень быстро.

      На вебе это не может ни когда работать быстро. Точнее может только в теории. Я ни разу в жизни не видел ни одного интернет магазина с полноценным юзабилити, который не тормозит. Чего говорить о сложных вещах? Даже в каком-нибудь сбере большую часть времени оператор не делает что-то полезное, а смотрит на кручение каких-нибудь ожидалок. А там работают, наверное, лучшие программисты из данной сферы. Что уж про остальных говорить?
      Он всегда хочет знать, что если вы пропадете по любой причине, его бизнес не сдох из-за вашего выбора технологий.

      Найти специалиста в любой области — не проблема. Только специалист стоит денег.


      1. Whuthering
        27.12.2017 11:06
        +1

        Я ни разу в жизни не видел ни одного интернет магазина с полноценным юзабилити, который не тормозит

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

        Честнго говоря, если почитать комменты на этом и других ресурсах о Сбертехе, многие люди на фразу о «лучших специалистах» бы в лучшем случае похихикали. Но — я там не работал, поэтому категорично утверждать не берусь.
        Да и опять же, вы, видимо, не понимаете, как вообще работают веб-технологии. Если у оператора крутиться прелоадер на экране — это не клиентский код тормозит, а, опять же, сервер или БД. Замените браузер на нативное приложение на Delphi или C++ — получите то же самое, только вместо зеленой крутилки там будет надпись «Пожалуйста подождите...» и курсор мыши с песочными часами.


        1. F0iL
          27.12.2017 14:03

          Я бы в качестве контр-примера привел Gmail и Google Docs.
          Работают реактивно, функционально, а тормоза могут быть только если есть серьезные проблемы со связью (но от такого и нативные клиенты не застрахованы, как сказали выше). У первого так вообще есть HTML-only вариант для совсем древних и слабых устройств.
          Вот они, настоящие веб-технологии.

          И в вебе за последние годы очень много добавилось именно для быстроты работы и оптимизации сетевого обмена. Хотите сами локально кэшировать нужные данные — WebStorage. Хотите получать с сервера обновления без постоянного поллинга — WebSockets. Хотите выполнять тяжелые операции с данными — WebWorkers, WebAssembly. А GraphQL позволяет разумнее продумать API, чтобы получать сразу все только нужные данные.


        1. akadone Автор
          27.12.2017 19:33

          Замените браузер на нативное приложение на Delphi или C++

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


          1. michael_vostrikov
            27.12.2017 22:17

            Хотите эксперимент?) Вы даете мне тестовую базу с обезличенными данными и несколько скриншотов текущего интерфейса, а также ТЗ с описанием работы этого интерфейса. А я попробую сделать аналог на веб-технологиях. Ну или честно скажу что не получилось / неохота / нету времени. Если получится, сравним скорость работы интерфейса и скорость взаимодействия с сервером.


          1. Whuthering
            27.12.2017 23:03

            не ставя в него i5

            Звучит как пустой треп. Вам уже далеко не один человек сказал, что i5 для такого вообще не нужен.
            (без лишних обращений на сервер как минимум).

            Каким образом? Локальный кэш, подписка на обновления? Веб/не веб здесь снова не причем — выше вам уже написали, что на современных HTML API's при желании точно такое же сделать не так уж и сложно.


  1. Whuthering
    26.12.2017 23:09
    +1

    Но дальнейшего развития проект не получил. Заказчик указал следующие к тому причины:
    Запуск “на холодную” курьерского приложения 4 секунды. Слишком долго.
    Надо менять язык программирования и полностью переписывать всё из-за п.1.

    Мне кажется, второй пункт был все-таки поводом, а не причиной.
    Просто достаточно поставить себя на место заказчика. Вы сами правильно отметили, что ERP-система должна быть легко и эффективно масштабируемой и расширяемой.
    А теперь представьте с позиции заказчика, что через N лет вы внезапно запросите за свои услуги поддержки и доработки в 5 раз большую сумму чем раньше, или уедете жить в другую страну, или вас автобус собьет. Нужен будет кто-то, кто продолжит работу, и это проблема.
    Ни для кого не секрет, что Delphi сейчас по сравнению с альтернативными технологиями крайне непопулярен ни в отрасли, ни в сообществе, ни на рынке труда. А специалисты гораздо охотнее берутся за работу, опыт которой будет ценен для них в дальнейшем. Плюс, у вас свой скриптовый движок (при том что есть куча широко используемых изначально интерпретируемых языков — JS, Python, etc., а выше вон вообще 1С упомянули), свой инструмент рисования диалогов (при том что есть куча широко используемых биндингов и библиотек для упомянутых ранее интерпретируемых языков), не очень красивый код (одно-двухбуквенные имена переменных, несоблюдение стандартов оформления, магические числа вместо констант, и т.д.), и скорее всего отсутствие подробной документации — в итоге заказчику придется долго искать того, кто согласится работать и разбираться со всем этим, и щедро мотивировать его на эту малоприятную и неблагодарную работу.


    1. akadone Автор
      27.12.2017 03:16

      Язык программирования — это лишь инструмент. И правильный выбор инструмента для решения определённой задачи — это основной залог успеха. Да, есть те, кто освоил отвёртку, зубило, даже дрель, НО, не освоил банальный молоток. И им вести за собой скульпторов?
      Для успешности надо владеть разными инструментами. Лично я пол года назад вообще не знал что такое RTTI, слабые ссылки, и прочая «муть» из современного Delphi. Мои основные языки разработки были c++/Java/C#, я разрабатывал VR решения, занимался OpenCV/SLAM позиционированием, реверс инжинирингом, из особых свежих моих достижений был самый эффективный лендинг для 4k в VR среди конкурентов в мире к примеру.
      То есть как-бы дорогущая Rad Studio — это вообще не мой профиль. Естественно я сто раз подумал, перед тем как выбрать Delphi. Отдать денег ведь надо было много за просто лицензию разработчика. Но нету ей альтернативы в этой области. Просто нет. Есть потуги мелко-мягких: xamarin, есть Qt. В первом случае слишком много проектов за последние 10 лет MS выкупала и уничтожала, что бы как-то серьёзно ставить на xamarin. Ну а Qt — интерфейс кросс-платформенный, но имеет слишком много ограничений. Ну и всё. Нет больше кросс-платформенных решений кроме html

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

      Нет. Кодеры берутся за работу, на которую они способны устроиться. А разработчики пишут, что разработали такую-то сисетму. И во-втором случае ЯП — это лишь уточнение.


      1. Whuthering
        27.12.2017 11:13

        Нет. Кодеры берутся за работу, на которую они способны устроиться. А разработчики пишут, что разработали такую-то сисетму. И во-втором случае ЯП — это лишь уточнение.

        Звучит полностью оторовано от реальной жизни. «Разработчики» могут написать все что угодно, вот только это не сильно поможет. Попробуйте устроиться на позицию Senior Developer'а, например, в какой-нибудь суровый и интересный геймдев-проект, ядро которого пишут на C++, при этом скромно сказать, что C и C++ вы не знаете вообще и в жизни на них не разрабатывали, но делали игры под Android на Java. На вас в худшем случае посмотрят как на идиота и укажут на дверь, в лучшем — предложат позицию джуниора.


        1. akadone Автор
          27.12.2017 19:42

          Я без проблем могу дома за недельку создать простенькую игру на c++, попутно изучив основные тонкости, показать код на собеседовании. Там единственная разница скорее всего будет, что вместо OpenGL надо будет применить DirectX, или что-то абстрактное типа Unity/Unreal. Шейдеры везде одинаковые, тени, освещения тоже. Вопрос будет лишь в синтаксисе и API.
          Лидом конечно сложно устроиться, а сеньёром — без проблем.


          1. Whuthering
            27.12.2017 23:08
            -1

            Я без проблем могу дома за недельку создать простенькую игру на c++

            Ни разу в жизни до этого на нем до этого не разрабатывая?
            И сразу писать сложный код, который пойдет в продакшн для продукта, критичного к быстродействию и стабильности? Ба, да вы настоящий джедай, что вы делаете на хабре, вас давно ждут в лучших мировых компании гейм-разработки. Ну или пишите книгу «C++ за 7 дней», будет бестселлером.


  1. zhavoronok
    27.12.2017 05:48

    Одному мне кажется, что из за проблемы с 4-х секундным стартом курьерского приложения внедрения ERP не отменяют? Не, я все понимаю, но 4-е секунды же… Если исходить из того, что автор написал про свое «ERP», то оно должно было экономить/зарабатывать, но 4-е секунды в приложении, это фигня, полная, по крайней мере, пока доставка выполняется по 40 минут.


  1. zhavoronok
    27.12.2017 06:40

    Вам тут несколько раз уже писали, но вы или не хотите или не можете понять.
    С точки зрения Заказчика или менеджера, чтобы получить максимум прибыли, важно с помощью автоматизации: во-первых, выжать максимум из имеющихся ресурсов — это достигается оптимизацией производственной цепочки и балансировкой ресурсов; во-вторых, чтобы полученная «автоматизация» жила и могла развиваться. И когда Заказчик адекватен и работает вдолгую, то второму вопросу он уделяет внимания даже больше, чем первому, потому что это окупаемость инвестиций. Если они не окупятся, то эта игрушка никому не нужна.
    С позиции менеджера скажу вам так, собственные разработки программистов одиночек на Delphi сейчас никому не нужны — это дорого, рискованно и неэффективно. Если мне нужна будет ERP, я охотнее вложу в 1С, даже если это будет дороже. Но покупая такое решение, я буду покупать не вашу способность писать код по моим/вашим ТЗ, а чью то экспертизу, которая уже обкатана и показала эффективность. Заказчик в большинстве случаев не знает как автоматизация может ему помочь (реально) и его бухгалтера/менеджеры/закупщики/повара/и пр. тоже не знают и они никогда не дадут вам нормального ТЗ. Но и инвестировать в технаря-программиста, который на вашем проекте ничем не рискует, а делает себе коробку, чтобы потом продавать и зарабатывать — глупо, потому что риски.
    А по поводу того, что делать с вашей разработкой — ну тут вариантов то не много. Если коротко, то читайте про развитие стартапов, в вашем случае, я другого пути не вижу. Если это рынку не надо — оно и не взлетит.


  1. michael_vostrikov
    27.12.2017 14:38

    но в данном случае мне, во-первых, хотелось получить единый код на всех устройствах

    Какой именно код в итоге остался общим? Вы ведь сделали скриптовый язык на сервере.


    спасибо, что исходники компонент дельфи доступны и там можно легко поправить заголовок http не заморачиваясь с raw socket

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


    их программа раз в минуту опрашивает сервер, и, если есть новый заказ, то печатает pdf

    То есть в ответе от сервера возвращался только pdf? Никаких JSON или XML? Решение с парсингом PDF выглядит странно.


    Если координат нет, геокодируем

    А почему сразу нельзя было геокодировать, без ФИАС? Ответы складывать в кэш, кэш постепенно наполнится, и будет то же самое, только без дополнительной интеграции.


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

    То есть обращения к серверу в процессе работы все же есть? А как данные выгружаются из кэша? Допустим оператор начнет пролистывать все заказы за последние полгода с целью найти какой-то конкретный.


    всем подписчикам придёт об этом уведомление с новыми данными

    Как решается вопрос когда у одного из клиентов в этот момент сеть недоступна? Он потеряет обновление?


  1. michael_vostrikov
    27.12.2017 14:44

    Несколько замечаний в целом.


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

    Скорость работы таких систем зависит от скорости ввода-вывода, а не от компилированности.


    Вдруг такое сочетание «улица-дом» уже встречалось, тогда берём координаты оттуда.

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


    но принять данные не возможно ни в какой форме

    Сам не пробовал, но то что сходу нашлось: чтение из window, чтение поля формы


    CurOrderState := GetNewValueF('Orders','OrderState');
    LastOrderState := GetOldValueF('Orders','OrderState');

    В современных подходах у вас есть объект класса Order и данные запроса, и вся эта куча кода превращается в order.state и request.state.


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

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


  1. bipiem
    27.12.2017 15:12

    Вот как! EPR в одиночку написали. А всякие там Enterprise Architecture и BPM использовали? Неужели обошлись без VAD, EPC, BPMN, BPMS? Особенно последних, этих «очень гибких» и «популярных и простых технологиях»?

    Брали бизнес-логику прямо «голыми руками» и сразу в код? Неужели действительно EPR так можно «состряпать»? Вроде бы как понятие «Enterprise» в аббревиатуре ERP к этому обязывает.

    Может быть, получится нарисовать описание «архитектуры предприятия» Вашего ERP, как это предлагается в третьем разделе https://habrahabr.ru/post/345424
    Или вообще любая ERP никакого отношения к ЕА и BPM и прочей алхимии не имеет?