среда, 4 ноября 2020 г.

Эффективность по Skunk Works

 Прочитал "Skunk Works. Личные мемуары моей работы в Локхид"

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

История SkunkWorks в первую очередь взрывает своей эффективностью. Принципы работы которыми делится Бен Ричи (глава SkunkWork в 70-80х) не являются откровением как минимум со времен "Мифического человеко-месяца". Однако книга на столько яркая, что заставляет еще раз оглянуться на разработку в которой участвуешь и задуматься о том, куда уходит время, так ли нужны нам эти митинги, таски, отчеты, код ревью, планирования, ретроспективы для создания продукта. Что если просто выбросить хотя бы половину из этого миллиона ритуалов? 

SkunkWorks - маленькое секретное подразделение Локхид, которое могло строить прорывные проекты с безумно высокой эффективностью. U2 полетел за 8 месяцев, SR-71 Blackbird - самолет способный в 62 году продолжительное время летать на 3 Max разработала команда из 75 инженеров-проектировщиков, программа прототипа F-117A от идеи до первого полета за каких то 30 млн. $  и 2 года.

Как команда из меньше чем 100 инженеров могла создавать проекты оставившие такой существенный след в истории? Сравните их со списком фич последней мажорной версии вашего продукта.  

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

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

Но у них было другое:

  • Повернутость на минимизации всей лишней деятельности.
  • Устранение преград для коммуникаций (от слесаря до инженера-проектировщика расстояние броска камня, от специалисты до специалиста расстояние вытянутой руки)
  • Высокопрофессиональный коллектив, лучшие из лучших.
  • Высокая мотивация и сплоченность коллектива, несмотря на мало комфортные условия работы. Что являлось мотивом для профессионалов? Работа в коллективе профессионалов, интересная работа, результат. Одно тянет другое.
  • Максимальный уровень свободы, минимальный уровень бюрократизма
  • Открытая среда - "Мы поощряли наших людей работать творчески, импровизировать и пытаться использовать нетрадиционные подходы к решению проблем и не мешали им."
  • "Мы стремились достичь эксплуатационной надёжности Шевроле, а не совершенства Мерседеса. За 20% усилий достичь 80% результата. Имей бы мы тогда сегодняшние мощные компьютеры, это бы ускорило проектирование и упростило бы испытания, но совершенство редко было целью Skunk Works. Если мы ошибались в расчётах на полкилограмма или на градус, это не сильно беспокоило нас."
  • Если надо нарушить правила - значит надо нарушить. Это не было проблемой при должном уровне компетенции, которая впрочем падала по мере роста.
  • "Всеобщее управление качеством". За контроль качества ответственны все причастные к процессу создания изделия.
  • "Уникальные материалы или детали должны избегаться,  везде где возможно. Уже готовые детали должны использоваться даже в ущерб лишнему весу"
  • В начале дешевый прототип.  

 
Кто то увидит здесь отголоски Agile, XP, Lean. Да! Все старо как мир. А еще история близки в том, что Agile тоже мало у кого работает.

Одно время, Бена Ричи сманивал Нортроп. И вот, что ответил Бену Келли:

“Чёрт возьми, Бен, я не верю ни одному слову, которое этот парень тебе сказал. Я поставлю своё ранчо на то, что Нортроп не создадут свой собственный Skunk Works. Компания даёт пустые обещания, потому что видит, насколько успешны мы. На самом деле менеджеры не верят в идею независимых подразделений, где из-за секретности они не могут точно знать, что происходит внутри. Не обманывай себя, у нас в менеджменте тоже есть люди, которых возмущаю я и наша независимость. Люди из аэрокосмической промышленности, даже уважающие нашу работу, хорошо знают, что чем меньше людей работает над проектом, тем меньше дохода можно получить от крупного правительственного контракта и возрастающих издержек. Сохранение небольшого количества людей снижает возможности для повышений. Чёрт, на главном заводе они дают повышение за большее количество людей, находящимся под руководством; я даю повышение тем, кто контролирует меньше людей. Это означает, что такие люди делают больше и принимают на себя больше ответственности. Но большинство руководителей думает совершенно другим образом. Руководство Нортроп ничем не отличается от всех остальных в этом бизнесе: все они пытаются построить империю, потому что именно так их учили делать. Эти парни - сплошь эксперты в прикрывании своих задниц путём выноса решений на голосование. Они никогда не согласятся создать подразделение, которое абсолютно не будет в них нуждаться. Они играют в игру под названием “Контроль”, и если Skunk Works действительно работает, как надо, то контроль это именно то, что они не получат."


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

"Любая компания, чьё положение зависит от разработки новых технологий, должна иметь в своём составе Skunk Works; сейчас существует примерно пятьдесят пять подобных подразделений в различных отраслях промышленности – это не очень много. Но если в Локхид Skunk Works был чрезвычайно успешен, почему сотни других компаний не попытались сделать тоже самое? Одна из причин, по-моему, заключается в том, что большинство других компаний не понимают концепцию, задачи и ограничения, в то время как многие другие не хотят предоставлять свободу и независимость, которые являются необходимыми компонентами для успешного функционирования предприятия типа Skunk Works."

пятница, 24 мая 2019 г.

Самый важный процесс

Если бы меня сейчас спросили, какой самый важный процесс в компании, то ответил бы: работающий процесс. Но работающий процесс это курица или яйцо? Тогда мой ответ ретроспектива - достаточная отправная точка для работающего процесса. Что у вас? Скрам, аджайл, канбан, тестирование, какая модель зрелости, чем там сертифицированы - ни как не подходит под  термин "самый важный процесс".
Есть ли у вас работающая ретроспектива, работает ли обратня связь, есть ли лифт-матка для процессов? В конечном итоге вопрос обратной связи главный в теории автоматического управления и динамических системах.
В какой то момент осознаешь, что список когнитивный искажений знать полезнее, чем список шаблонов проектирования или умение забивать гвозди.

суббота, 26 января 2019 г.

"У нас нет ресурсов для ревью кода" (с)


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

Попалась отличная вводная статья про управление качеством продукта https://vsavkin.livejournal.com/6050.html. Без воды,  где все снято как с языка.
Если в кратце, тезисно по ней:

К прописным истинам можно отнести:

  1. Качество процесса разработки определяет качество разрабатываемого продукта!
  2. Чем позднее дефект обнаружен, тем дороже стоит его исправление
  3. «повышение качества системы снижает расходы на её разработку».
    Думаю этот пункту можно добавить несколько примечаний, но в общем случае согласен.
     
Что особо отметил для себя:
  1. Только на тестирование нельзя полагаться не только потому, что это позднее выявление дефектов, но и потому что большинство видов тестирования имеет низкий КПД.
  2. Формальная инспекция кода эффективный инструмент (наш выбор это использование в ревью кода/дизайна практик формальной инспекции).

Интересную статистику подтверждающию Макконела по поводу сравнения эффективности инструментов можно найти в слайдах  автора. Средняя стоимость поиска и исправления дефекта:
  1. Инспекция - 9 чел-часов
  2. Интеграционное тестирование -  21 чел-часов
  3. Системное тестирование - 34 чел-часов

А так же для мнемоники притча
http://losev-al.blogspot.com/2013/12/kpi.html#

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

понедельник, 19 ноября 2018 г.

Список из рекордов на коленке

Честно подсмотрено.

THeader = record
  x,y,z: TMyRecordField;
  NextLabel: packed record end;
end;

На сколько прекрасно, на столько и отвратительно. Но восхищает однозначно хотя бы тем, что это вообще работает. Если что, то NextLabel это ссылка на следующию записью.

воскресенье, 18 ноября 2018 г.

Парное_программирование VS ревью_кода


 Данная заметка - реакция на статью http://alexnesterov.com/code-review/, где практика code review рассматривается как антипаттерн, а парное программирование как способ решить задачи ревью кода правильно. 
Конечно же, у парного программирования и код ревью есть пересекающееся множество целей. Но парное программирование не в силах полностью закрыть потребность в ревью кода.

Минусы парного программирования

Минусы full-тайм парного парного программирования которые сразу бросаются в глаза:
  1. Практика full-тайм парного программирования доступна не всем компаниям:
    • Не каждый кандидат может/согласится работать в такой методологии. 
    • Вопрос организации пар тоже не самый простой.
    • Все остальные процессы в компании должны затачиваться под парное программирование: организация рабочего места, распорядок дня (приход-уход, удаленная работа, больничные, обеды).
    • Т.е. отрезаем себя от части рынка труда и добавляем дополнительные сложности. 
  2. Фул-тайм парное программирование не всегда эффективно. Есть множество достаточно простых  или рутиных задач в которых от создание пары не получить буста в производительности или качестве. Т.е. фул-тайм парное программирование просто получение максимального качества без учета экономической обоснованности. 
  3. Парное программирование не решает всех задач ревью код
    • Как происходит распространение знаний между парами? Ротациями пар? На сколько это эффективно и какой лаг? 
    • Код ревью под парами (инструменты настроены и все знают как ими пользоваться) позволяют в любой момент подключить нужное количество ревьюверов в асинхронном режиме) 

Золотая середина?

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

Мифические проблемы ревью кода

Неправильное использование любой техники может привести к ее негативному восприятию.

Потеря контекста

Это не проблема, а сигнал что в процессе разработки что то не так. Контекст и мотивация автора должна быть понятна из ревью. Про это у меня есть статья http://cemick.blogspot.com/2015/08/svn-git-git.html
Программист  - не археолог разбирающий наскальные записи прошлых поколений. Если контекст и мотивация не понятная на ревью, она будет не понятна через неделю другому программисту который попадет на этот участок кода и автору  уже через месяц.
Ко всему прочему мы к ревью часто прикладываем ссылку на поднятый инстанс или бинарник, что бы ревьювер мог проверить работающее приложение, если есть в этом потребность. 

Это не баг, это фича

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

Отсутствие эмпатии

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

Нарушение потока автора

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


Что же такое ревью кода

  1. Это гибкость
    Можно организовать менторство.
    Можно в любой момент подключить нужное количество людей с известными всем правилами обсуждения и документированием.
    Можно выпонять асинхронно и синхронно. 
  2. Контроль соблюдения стандартов и правил оформления кода 
  3. Распространение знаний о важных изменения в проекте. Об изменения в архитектуре и в сквозной части функционала необходимо извещать все заинтересованные стороны.
  4. Повышение квалификации 
  5. Сохранение дополнительной метаинформации по коммиту: обсуждение в рамках ревью остается задокументированным. 
  6. Распределение нагрузки по контролю за кодовой базой или распространением информации с тимлида или начальника отдела на всех. 


понедельник, 28 марта 2016 г.

Почему тип анонимных функций не всегда полезен или о проблема присвоения reference to типу неанонимных функций

Сегодня снова об особенностях анонимных функций.
Два предыдущих поста:
  1. Просто баг в коде или особенность счетчика ссылок в замыканиях
  2. Немного про замыкание ( Одно замыкание на несколько анонимных функций в одном контексте)

  У типа анонимный функций есть замечательная возможность. В качестве обработчика можно присваивать не только анонимные функции, но и обычные методы и статические функции. Казалось бы, нет причин почему не использовать тип reference to всегда.
Однако есть ситуации, когда reference to тип может сыграть злую шутку. И я сейчас не про вопрос производительности, о котором я думаю большинство осведомлено. 
Проблема может возникнуть при передаче обычной процедуры или метода в параметр с анонимным типом. Покажем на примере. 
Наиболее распространенный вариант использования процедурных типов в реализации подписки на события.
  Пусть есть какой-нибудь список EventHandlers, и конечно же, как у правильных хипстеров он будет параметризован типом анонимной функций TList<TProc>. 
Заведем два метода для возможности подписаться на событие и отписаться от него:  Subscribe(AHandler: TProc) и Unsubscribe(AHandler: TProc): Boolean соответственно. Однако, крайне вероятно, вас постигнет неудача если в качестве обработчика вы используете неанонимную функцию.  По крайне мере отписаться вы уже не сможете. 

Вот код примера:
program ReferenceToProc;
{$APPTYPE CONSOLE}
{$R *.res}
uses
  System.SysUtils, System.Generics.Collections;
var
  eventHandlers: TList<TProc>;

  procedure Subscribe(AHandler: TProc);
  begin
    eventHandlers.Add(AHandler);
  end;

  function Unsubscribe(AHandler: TProc): Boolean;
  begin
    Writeln(eventHandlers.IndexOf(AHandler));  // 0
    Result := eventHandlers.Remove(AHandler) >= 0;
  end;

  procedure HandlerProc;
  begin
    Writeln('Вызов статической процедуры');
  end;

var
  proc: TProc;
begin
   eventHandlers:= TList<TProc>.Create;

   proc := procedure()
     begin
       Writeln('Вызов анонимной функции')
     end;

   Subscribe(proc); // Подписываемся анонимной функцией
   Writeln(Unsubscribe(proc)); // Метод вернул True, Успех:)

   Subscribe(HandlerProc); // Подписываемся не анонимной функцией
   Writeln(Unsubscribe(HandlerProc)); // Метод вернет False Fail:(
   FreeAndNil(eventHandlers);
   readln;
end.

  Вызов Unsubscribe  в строке  Writeln(Unsubscribe(HandlerProc)); вернет False. Причина впрочем прозаична, вызов метода HandlerProc заворачивается в анонимную функцию и каждый раз новую. Потому функция, которую подписали на событие, будет отличаться от функции, которую пытаемся отписать.

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

  Получается, что хранить обработчики лучше как TMethod, но если все же хотим уметь подписывать универсальные обработчики (анонимные и неанонимные), тогда придется для каждого типа писать свою логику сохранения в список и вызова обработчиков. Это будут либо overload методы, либо будем использовать Rtti  и методы параметризированные типом.
  TEvent = class
    events: TList<TMethod>;
    class procedure Subscribe(AProc: TProc); overload;
    class procedure Subscribe(AProc: TProcedure); overload;
    class procedure Subscribe<T>(AProc: T); overload;
  end;

  А для преобразования анонимного метода в TMethod потребуется сочинять что то вроде того, что написано в Spring4D в Springs.Events.pas:

procedure MethodReferenceToMethodPointer(const AMethodReference; const AMethodPointer);
type
  TVtable = array[0..3] of Pointer;
  PVtable = ^TVtable;
  PPVtable = ^PVtable;
begin
  // 3 is offset of Invoke, after QI, AddRef, Release
  PMethod(@AMethodPointer).Code := PPVtable(AMethodReference)^^[3];
  PMethod(@AMethodPointer).Data := Pointer(AMethodReference);
end;

function TEvent.Cast(const handler): TMethod;
begin
  if fTypeInfo.Kind = tkInterface then
    MethodReferenceToMethodPointer(handler, Result)
  else
    Result := PMethod(@handler)^;
end;