Как стать автором
Обновить

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

Время на прочтение5 мин
Количество просмотров2.9K
Всего голосов 3: ↑2 и ↓1+2
Комментарии20

Комментарии 20

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

А если задача была поставлена изначально неверно или продукт вообще оказался не востребован на рынке? Или если разработчик делает хорошо свою работу, но ему нет дела до того как и кто этот продукт продает? Должен ли он задумываться об этом? Или компания не может построить стратегию продажи?

А если компания заработала оверденег на продукте? Значит ли это что разработчики получат справедливый процент от его продажи? И если нет то в чем будет выражаться их материальный успех?

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

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

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

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

1) если продукт не востребован на рынке , то всё просто закрыли и всё , обычно более проблемно - если продукт зарабатывает 1 млн в месяц и не больше и сделан из дерьма и палок , что делать ? оставить и ждать пока он совсем бабахнет или вкладываться в рефакторинг ? или вообще закрыть , чтобы сфокусироваться на более успешных вещах
поэтому здесь не так всё просто , мы стараемся либо рефактринг , либо вообще закрыть
2) если разработчик делает работу хорошо , но нет дела как работает продукт - ну сложно будет делать продукт и не вовлекаться в работу при этом. Можно просто либо найти команду где продукт интереснее , либо заняться инфраструктурными задачами - core сервисы и тп
Разработчик должен прежде всего задумываться о том чего он хочет, хочется работать с более классным продуктом => искать другую команду , не хочется вообще с бизнесом сталкиваться => core и здесь хорошо и бизнес интересный - > ну тогда надо продукт тоже понимать иначе это ерунда
3) справедливый %% от прибыли вообще понятие абстрактное , у каждой партии он свой , акционеры вложили деньги , сейлзы и маркетинг продавали , операционисты поддерживали работу компании , инженеры из ИТ компы всем ставили и сеть тянули, безопасность следила, чтобы не было проблем иначе вся прибыль в трубу (главное не деньги , главное безопасность - я вот с этим согласен на самом деле ) , ну и соответственно команда разработки сделала классный продукт , какой справедливый %% она получит ? действительно будут всякие повышенные премии и легче в корпоративной иерархии продвигаться, быстрее оклад вырастет и в больших %% , но не более

А давайте заведем практику - вместо инъекции зависимостей, будем напрямую инициализировать их из контекста во всем приложени.

Не уловил идею. Как инициализировать зависимость из контекста?

Вы про теорию или практику? Русский язык весьма богат и одно и то же можно называть разными словами. Как я понял вашу идею, Spring делает то о чем вы говорите, про другие IoC container фреймворки сказать не могу. А если вы говорите о другом, тогда встречный вопрос: "Является ли это мейнстримом в Java стэке?". Если порассуждать шире, почему в enterprise практически не пользуются вчера изобретенными или не прижившимися технологиями. Потому что у мейнстрим технологий понятны плюсы и минусы, найдены обходные пути, на рынке много людей, которые знакомы с ней. Поэтому если кому-то в голову пришла какая-то идея - отлично, возможно она перевернет индустрию, внедрите ее сначала в стартап, когда она там обкатается, тогда enterprise начнет к ней присматриваться

Спасибо большое за статью, очень интересно читается!

Но не очень понятен пункт с переходом от синглтонов к бинам. Емнип, брать явно из контекста бин по его классу далеко не best practice. Что мешало в рамках конкретной бизнес-задачи переводить затрагиваемые синглтоны в бины?

Давайте уточним. Не очень понятен или не очень правилен?) Попробую ответить на оба мнения.

1) Во вспомогательном классе мы инжектим ApplicationContext в статическое поле класса. И через статический метод предоставляем доступ к его методу getBean(). Таким образом из любого места кода (который выполняется в рантайме и после загрузки Spring контекста) мы можем получить любой Spring бин и работать с его методами. В итоге при рефакторинге вы и делаете самописный синглтон спринговым бином, но во всех местах где он уже используется вы просто заменяете MySingleton.getInstance() на Context.getBean(MySingleton.class)

2) Безусловно это не best practice. Но тут нужно понимать ограничения. А ограничения тут такие - если вы спринговым бинам с одинаковыми классами дадите разные имена, надеясь что их потом можно подцепить через Qualifier, то вас будет ждать разочарование. А если один класс - один бин, то ничего страшного. Но! Конечно этот подход был временной мерой, постепенно, когда все больше и больше классов переводились на спринг бины мы уже уходили и от этого "интересного решения" на стандартный спринговый подход.

Что мешало в рамках конкретной бизнес-задачи переводить затрагиваемые синглтоны в бины?

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

Развернуто и понятно) Спасибо большое за разъяснение!

Избавьтесь от ООП и жизнь станет проще...

Спасибо за совет. А какую парадигму предлагаете?

Да простейшую. Контейнеры состояния и массивы-наборы команд-обработчиков. Не очень помню что там в Java, но наверное можно примерно вот так:


public interface Command
{
  void Execute(HashMap<String, Object> state);
}

public class MakeOperationId implements Command {

  public void Execute(HashMap<String, Object> state) {

    if(state.containsKey("error")) return;

    int length = (Integer)state.get("operationIdLength");

    byte[] bytes = new byte[length];

    Random generator = (Random)state.get("randomGenerator");

    generator.nextBytes(bytes);

    DatatypeConverter converter = 
      (DatetypeConverter)state.get("DatatypeConverter");

    state.put("operationId", converter.printHexBinary(bytes));    
  }
}

public class ErrorInterceptor {
  public static void Execute(Command command, HashMap<String, Object> state) {
    try {
      command.Execute(state);
    }
    catch(Exception error) {
      state.put("error", error);
    }
  }
}

Command[] handlers = new Command[] {
  new MakeOperationId(),
  new ParseRequestBody(),
  new ValidateRequestBody(),
  new GetUserCredentials(),
  new GetUserPermissions(),
  new GetInvoicesPendingPayment(),
  new GetBankStatement(),
  new MakePaidInvoices(),
  new SavePaidInvoices(),
  new MakeResponseContent(),
  new SendReport(),
  new ReportError()
};

HashMap<String, Object> operationState = 
  InvoiceReconciliationOperationState.make(applicationState);

for(Command command : handlers) {
  ErrorInterceptor.Execute(command, operationState);
}

Про Простейшую парадигму ничего не слышал :) Знаю Процедурную, Объектно ориентированную и Функциональную. И как верно заметил Робер Мартин каждая из них нас по-своему ограничивает. То что вы привели в примере кода, это паттерн Command (Команда или Действие), но ваш собственный пример использует Объектно Ориентированное Программирование (interface, class, new OperationId()).

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

Ну поскольку в вашей публикации речь идет о Java, то в примере кода я естественно использовал доступные возможности Java. Ну а поскольку в Java нельзя просто объявить процедуру ни в глобальной области видимости, ни в области видимости модуля, то я конечно оформил поведение используя ООП, которое к Java приколочено гвоздями. Я мог бы то же самое написать к примеру на Javascript и там бы не было ни классов ни интерфейсов ни ключевых слов new.

Ну да и ладно. Не заметили вы парадигму, ну и бог с ней. Конечно пользуйтесь ООП на здоровье, если вам так проще и удобнее. Я не навязываюсь.

Можно и на JS. Про первую часть ок, допустим что это из-за реализации Java.

Но ООП никак не мешает использованию этого паттерна (или как вы называете парадигмы), а даже помогает.

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

А чем ООП в данном случае помогает?

Погодите. Вы вначале предложили избавиться от ООП. Я спросил что в замен. Вы предложили шаблон проектирования, который можно использовать и в ООП и в процедурном программировании (может и в функциональном). Когда я указал что это разные уровни и одно другому не мешает, вы согласились, что конечно не мешает. Зачем тогда избавляться от ООП, если он не мешает? :)

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

:-) Я так и не понял в чем преимущество ООП :-)

В том, что поведение надо упаковывать в классы? В моем примере все классы же по сути вырожденные. Это просто контейнеры для единственного метода Execute. Ценность самих классов в моем примере равна нулю. В них нет ни приватных методов, ни свойств. У них даже названия не как у нормальных классов HttpClient или DataContext, а как у обычных функций makePaidInvoices, sendReport.

Ну то есть вот есть у нас реальный процесс. Ну скажем вот такая история:

Как система, я хочу выполнить операцию сверки оплаты выставленных счетов

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

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

Отвечаю на второй вопрос. ООП полезен тем, что можно оперировать объектами. У объекта может быть множество полей и они не "висят в воздухе" как глобальные переменные, а принадлежат конкретному объекту. И это легко маппится на реальность. Есть человек у него есть Имя Фамилия Отчество (в некоторых странах), дата рождения и др. У человека есть адрес фактического проживания (у большинства), который состоит из страны, населенного пункта, улицы, дома и др. У человека есть документ удостоверяющий личность. У документа есть номер и дата выдачи и др. И еще много-много других параметров. А ещё автомобиль и другое имущество. И все это важно в контексте оформления и учёта договоров страхования. Как оперировать этими параметрами и описывать бизнес логику в коде также интуитивно понятно как в ООП?

Касательно вашего последнего вопроса по сверке. Я не знаком с этой предметной областью и не знаю всех параметров, по которым нужно сверять счета. Но если там 1 или 2 параметра, то это частный случай. Конечно, чтобы написать, например, Калькулятор, то ООП тоже не обязателен. Но возвращаясь к тому с чего начинали: почему не использовать поход, который обладает большей мощью и позволяет решать и простые, и сложные задачи

Зарегистрируйтесь на Хабре, чтобы оставить комментарий