Тег «программирование»

Как ускорить код-ревью

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

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

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

Что такое код-ревью; какие у него цели?

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

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

Разработчик Олег пушит свои изменения напрямую в мастер, откуда эти изменения выезжают в продакшен. Если Олег сделал всё правильно и ничего не забыл, то нам повезло и мы ускорили пайплайн в этом месте. Но при этом есть разработчица Александра, которой придётся пересматривать свои ещё не смёрженные изменения с учётом только что вмёрженных изменений Олега. Если вам кажется, что это просто — ну, да, запустить rebase origin/master действительно просто, но что если изменения Олега меняют предположения о системе, из которых исходила Александра? В таком случае автоматический ребейз может либо выдать мёржконфликт (и это будет хорошо! Это может заострить внимание на нарушенных предположениях), либо, что страшнее, молча сделать вид, что всё нормально, хотя изменения Олега и Александры работают по отдельности и не работают вместе.

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

Ключевой момент здесь: изменения меняют предположения о системе; под словом «предположения» я имею в виду изменения, которые обладают потенциалом «каскада», где потребуется менять какую-то ещё часть кода системы. Такие изменения можно грубо охарактеризовать, разбив их на три уровня:

  • уровень интерфейсов между горизонтальными (равноправными) частями системы. Например, «чтобы показать попап, надо нарисовать в своём компоненте <Popup>{popupContent}</Popup>».
  • уровень фич. Например, «мы хотим показывать попап в такой ситуации».
  • уровень платформы. Например, «наше приложение запускается в контейнере с Node.js такой-то версии».

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

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

В этом контексте часто говорят о time to market определенной фичи, но это не очень подходящая метрика: если мы релизим одну фичу в неделю, но зато её провели через конвейер за полдня, то у нас будет отличный ttm (зарелизили за полдня!), но отвратительный throughput (в неделю только одну фичу!).

Код

На самом деле мы хотим уменьшить latency и увеличить throughput одновременно. Это возможно за счёт снижения времени на код-ревью без снижения качества.

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

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

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

В код-ревью в целом можно выделить четыре стадии:

  1. Время от создания пулреквеста до начала ревью
  2. Время ревью, где ревьюер должен осознать суть изменений, на какие предположения опирается пулреквест, не нарушены ли они. (В плохих случаях здесь также идёт анализ кода на соответствие код-стайлу, в большинстве случаев это можно вынести на шаг 1 через автоматизацию)
  3. Время правок, где автор пулреквеста исправляет замечания с шага 2; после чего мы снова переходим на шаг 1, если только на шаге 2 не было никаких замечаний.
  4. Мёрж изменений, тестирование, релиз, потенциально — отлавливание проблем в продакшене.

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

Чтобы снизить количество такой переработки надо снижать количество потенциально изменчивых предположений внутри пулреквеста. Как самый простой способ: делать пулреквесты небольшими, потенциально даже меньше, чем фича (таким образом, для реализации и деплоя фичи в мастер должны попасть несколько пулреквестов). Это снижает вероятность переработки тем образом, что когда Олег приходит менять, скажем, Popup, он учитывает потребителей, которые уже в мастере, и может автоматически отрефакторить все вызовы попапа на новый синтаксис.

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

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

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

Но мы же не можем релизить половину фичи! — скажете вы, и будете отчасти правы, мы не хотим, чтобы пользователь увидел наполовину готовое. Для этого можно использовать фича-флаги, эксплицируя время разработки внутри кода. Можно автоматизировать удаление ненужного кода через несколько дней после финального пулреквеста.

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

Люди

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

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

Часто говорят о роли код-ревью в ещё трёх процессах: снижение code ownership, распространение знаний о коде, обучение best practices и программированию в целом. Это всё полезные цели, но если мы достигли точки, где код-ревью само по себе стало заметной проблемой, то стоит вынести, хотя бы временно, их из критического пути в асинхронные методы коммуникации (например, рассылки и чейнджлоги).

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

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

У людей помимо всего прочего есть свои biases, но у каждого человека их набор и их проявления более-менее стабильны, поэтому со временем можно составлять «портрет» ревьюера. Например, Игнат всегда находит, что откомментировать, в любом пулреквесте, поэтому назначая ревью на него, стоит предположить, что случится пинг-понг.

Большая картина

Теперь немного посмотрим на картину в целом: как определить, что процесс код-ревью выстроен хорошо?

  1. Ошибки в продакшене — редкость, и обычно связаны с непредсказуемыми факторами: код-ревью выполняет свою главную роль повышения стабильности.
  2. Код-ревью редко превращается в пинг-понг: ревьюеры правильно и полноценно коммуницируют замечания.
  3. Время прохождения код-ревью обладает небольшой вариативностью: не бывает гигантских или чрезвычайно сложных пулреквестов.
  4. В системе нет мест, которые страшно менять: у разработчиков есть вера в то, что код-ревью поймает возможные ошибки.
  5. Через ревью проходят как мелкие фичи, так и большие инфраструктурные изменения.

Каждый из пунктов при желании можно измерять и отслеживать — но стоит сравнивать проект только с этим же проектом, для каждой системы целевые значения метрик свои: требования к надёжности в NASA и стартапе разные.

Слишком длинно, давай вкратце

  1. Пулреквесты должны быть маленькими: меньше строк кода — меньше предположений — быстрее ревью,
  2. Пулреквесты могут быть на половинку фичи, используйте фича-флаги: ранняя фиксация предположений в мастере снижает вероятность их нарушения,
  3. Чем меньше ревью требует ручного анализа, тем лучше: разделяйте систему на независимые и отграниченные интерфейсами части, чтобы снизить количество необходимых предположений.

Руководство по программистским спорам

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

Прочитать это руководство, конечно же! Чтобы начать, нужно запомнить несколько простых правил.

Правило №1: язык — говно

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

— Джава хороший язык. — Да говно твоя джава!

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

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

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

Правило №2: бейте в слабые места

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

— Чё это джава говно?
закатив глаза Статическая. Типизация. Кошмар, как так можно вообще в (подставить год)?

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

  • Джаваскрипт: интерпретируемый язык с динамической типизацией, прототипной моделью наследования, сборщиком мусора. ПРИДУМАН ЗА ДЕСЯТЬ ДНЕЙ!
  • Джава: компилируемый язык со статической типизацией, классовой моделью наследования, сборщиком мусора. ОЧЕНЬ МНОГОСЛОВНО, БЕЗ IDE НЕ РАЗОБРАТЬСЯ.
  • Раст: компилируемый язык со статической типизацией, с автоматическим управлением памяти без сборщика мусора.
  • Кложура: компилируемый и интерпретируемый язык с динамической типизацией, сборщиком мусора.
  • Хаскель: компилируемый язык со статической типизацией, сборщиком мусора. НУЖНО ПОНЯТЬ МОНАДЫ, ЧТОБЫ ВЫВЕСТИ HELLO WORLD.
  • Эликсир: компилируемый и интерпретируемый язык со статической типизацией, сборщиком мусора
  • Си: компилируемый язык со статической типизацией, ручным управлением памятью.
  • Сиплюсплюс: компилируемый язык со статической типизацией, ручным управлением памятью и иногда автоматическим управлением памятью.
  • Руби: интерпретируемый язык с динамической типизацией, классовым наследованием, сборщиком мусора.
  • Не перечисленные выше: ДА ОН ЖЕ НИКОМУ НЕ НУЖЕН.

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

— И что хорошего в джаве? — На рынке полно разработчиков, легко найти работу. — Тебе что ли десять тысяч кодеров нужно? Лучше уж найти двоих-троих, зато самых клёвых. Да и какую работу ты джавистом найдёшь? То-то же.

Правило №2 поможет вам продержаться на ринге дискуссии до тех пор, пока собеседнику не надоест — тогда-то и надо объявлять победу.

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

Правило №3: объявите, что объективности не существует

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

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

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


Ну вот и всё, вы восхитительны и готовы участвовать на равных в спорах про языки программирования!

1

Обсценная лексика работает для этого ещё лучше, но не везде.

Правила хобби-проектов

Как и у многих программистов, у меня полно маленьких проектов, которыми я занимаюсь время от времени. Это может быть сайт, библиотека, решение каких-нибудь челленджей, сайд-проект или же просто «hobby project».

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

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

Когда текст ниже говорит «ты», я обращаюсь не только и не столько к тебе, анонимный читатель, сколько к себе. Я не говорю, что придерживаюсь этих правил всегда, но мне кажется, что это хороший фундамент.

Задокументировать архитектуру в ARCHITECTURE.md

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

Например, кусок из ARCHITECTURE.md Комлинка:

### Accounts

Контекст, отдельный от всего остального. Не должно быть зависимостей во вне (например, на Feeds).
Этот контекст занимается _пользователями_: регистрация через почту, через гитхаб, подтверждение аккаунтов, инвайты.

### Feeds
Контекст, который занимается _постами_ и комментариями к ним.

### Events
Контекст, который занимается _событиями_: например, конкретная встреча нодскула.

## Веб
### Вьюхи

Для каждой сущности должно в итоге быть несколько шаблонов:

1. Full. Entity with all related things.
   E.g. Post: includes Comments, includes Author, includes Group, etc.
2. Widget. When element is tightly related on one-to-one basis
   E.g. on Event page there would be Place widget.
3. List item. When we present a list of homogenous entities.
   E.g. On main page, we see a list of posts. On post page we see a list of comments.
4. Line. When we mention entity in passing.

Бессовестно написанный на смеси русского и английского — потому что я так думаю. (см. доклад Махоткина: надо меньше стесняться русского языка).

Это не финальная версия, и это не design upfront, как может показаться. По мере разработки улучшается понимание как должно быть, его и стоит документировать. Здесь же можно задокументировать важные моменты, которые почему-то плохо выражаются в коде.

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

Записать в README.md как запустить проект с нуля

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

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

Покрыть тестами то, что может сломаться

Чтобы не бояться менять то, что можно менять. Не надо целиться на стопроцентное покрытие тестами — но имеет смысл потестировать суть и самые важные флоу. Так что это не про юнит-тесты, а про интеграционные тесты и user acceptance тесты.

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

Деплоить одной простой командой

Хуже всего, когда пишут в твиттере, мол, сайт не работает, ты уже пофиксил — а как деплоить-то и забыл. Rsync? А какие флаги нужны? А на каком сервере оно сейчас лежит? (pun intended)

Хотя нет, ещё хуже — это когда процесс деплоймента звучит как «так, делаешь ssh на сервер, ищешь директорию, делаешь git pull, мёржишь конфликты, потом запускаешь вот такую команду…» У тебя и так много боли, не надо добавлять её ещё и деплойментом.

В каком случае правило помогает: Каждый. Чёртов. Раз.

Задокументировать создание серверов

Даже если в моменте кажется «да там дроплет создал, хуё-моё, постгрес накатил и скачал архивчик, делов-то», лучше описать процесс, пока можешь. Рано или поздно с сервером что-то случится, и, по законам Мёрфи, в этот момент уже будет поздно вспоминать.

Стоит описывать дистрибутив, пакеты, команды, как настроить сервис, надо ли делать что-то для persistence.

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

В каком случае правило помогает: Когда по каким-то причинам Облако превратилось в чужой компьютер, который не работает.

Вести роадмап вне головы и ввести цели

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

Роадмап на пару шагов вперёд помогает удерживать big picture в фокусе. Цели проекта помогут оценить, правильно ли идёт дело.

В каком случае помогает: Когда хобби-проект начинает расти.

1

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

Алгоритм произведения Карацубы

Один из самых простых алгоритмов для перемножения тебе рассказали ещё в школе: перемножать в столбик.

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

Дело в том, что складывать гораздо проще чем умножать.

Задача: перемножить два числа

На вход приходит два числа, $x$ и $y$, каждое из $n$ цифр. Случай, где надо перемножить числа с $n = 1$ тривиален, поэтому предположим $n >= 2$.

Как это сделать

Разобьём два этих числа пополам поциферно и назовём $a$, $b$, $c$, $d$. Это выглядит нагляднее на примере, перемножим $12$ и $34$: $12 \implies a=1, b=2$, а $34 \implies c=3, d=4$.

Из $a$ и $b$ легко собрать обратно $x$: $10^{n/2}a + b$.

Давайте запишем произведение $x$ и $y$ в этом виде, получим:

$$ x \times y = (10^{n/2}a + b) \times (10^{n/2}c + d) $$

И развернём скобки:

$$ (10^{n/2}a + b) \times (10^{n/2}c + d) = 10^{n}ac + 10^{n/2}bc + 10^{n/2}ad + bd $$

Вынесем $10^{n/2}$ за скобки:

$$ 10^{n}ac + 10^{n/2}bc + 10^{n/2}ad + bd = 10^{n}ac + 10^{n/2}(bc + ad) + bd $$

Пока всё хорошо и довольно понятно: чтобы получить результат, нужно посчитать $ac$, $bd$, $bc + ad$, подвигать разрядами ($10^{n}a$ — это $a$ с дополнительными $n$ нулями) и сложить.

Но дальше идёт то, в чём и заключается «фишка» алгоритма, мы не будем считать $bc + ad$ (это ещё две операции умножения!), давайте посчитаем $(a+b)\times(c+d)$ — это же всего одна операция умножения (и две операции сложения, но складывать «дешевле», чем перемножать). ($ac$ и $bd$ всё же придётся посчитать честно.)

Теперь развернём скобки у $(a+b)\times(c+d)$:

$$ (a+b)\times(c+d) = ac + bc + ad + bd $$

И вычтем $ac$ и $bd$ — тогда у нас останется $bc + ad$, что нам и нужно, и мы сможем дописать нужные нули и сложить все три величины, чтобы получить результат.

Таким образом, чтобы посчитать $xy$, нужно:

  1. Разбить $x$ на $a$ и $b$, $y$ — на $c$ и $d$.
  2. Посчитать $ac$.
  3. Посчитать $bd$
  4. Посчитать $(a+b)\times(c+d)$
  5. Посчитать $(4) - (3) - (2)$
  6. Сложить $10^{n}ac + 10^{n/2}((4) - (3) - (2)) + bd$

Пример: $60403122 \times 23224568$

Чтобы было нагляднее, давайте перемножим два числа, например, $60403122 \times 23224568$ (получается, что $n = 8$):

  1. Разобьём поциферно: $a = 6040, b = 3122; c = 2322, d = 4568$.
  2. $ac = 6040 \times 2322 = 14024880$
  3. $bd = 3122 \times 4568 = 14261296$
  4. $a+b = 9162; c+d = 6890; (a+b)*(c+d) = 63126180;$
  5. $$(a+b)*(c+d) - bd - ac = 63126180 - 14261296 - 14024880 = 34840004$$
  6. Сдвигаем и складываем:
  7. $10^{8}14024880=1402488000000000$.
  8. $10^{4}34840004=348400040000$
  9. $6.1 + 6.2 + bd = 1402836414301296$

Если удобнее в столбик, то вот:

  1402488000000000 (6.1 + 6.2)
+ 0000348400040000
------------------
  1402836400040000

  1402836400040000 ((6.1 + 6.2) + bd)
+ 0000000014261296
-------------------
  1402836414301296

И $1402836414301296$ и будет нашим результатом.

21 идея для разработчика

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

  1. Задача программиста не «писать код», задача программиста — решать бизнес-задачи, и «поиграться с новым фреймворком» зачастую не решает бизнес-задачу.
  2. Мы работаем с людьми, и только иногда пишем код, поэтому отношения между людьми — важная часть работы.
  3. Разработчики тоже люди, и подвержены всем тем же когнитивным ошибкам, что и все остальные. Стоит почитать про когнитивные ошибки, FAE, и книгу Канемана в отдельности.
  4. Постоянно сменяющиеся фреймворки появляются потому, что у нас нет идеального решения проблем, которые стоят перед фронтенд-разработчиками. Каждый следующий успешный фреймворк — шаг в интересном направлении в сторону идеала, стоит относиться к ним с точки зрения «что интересного этот фреймворк/библиотека привносит в мою работу».
  5. Разработчики не просто «пишут код», они участвуют в бизнес-процессах. Если в компании принят Аджайл, то нужно относиться к этому если не серьёзно, то как минимум с уважением.
  6. Код-ревью — важная часть процесса разработки. Нельзя быть хорошим разработчиком, но относиться к код-ревью халатно.
  7. Как программисты, мы несём ответственность за то, что деплоим. В том числе, и моральную. Не стоит делать неэтичные вещи.
  8. Пользователи — живые люди. Наши продукты и ошибки могут напрямую влиять на их жизнь, стоит осознавать последствия наших действий.
  9. Люди отличаются друг от друга, люди думают по-разному: что нам кажется сложным, бизнесу может казаться тривиальным — это создаёт конфликт, который приходится разрешать.
  10. Нужно нести ответственность за свои дедлайны, и если не укладываешься — идти передоговариваться.
  11. У задач есть два вида сложности: внутренняя и внешняя сложность. От первого вида сложности не избавиться, он есть в задаче изначально; второй привносим мы, городя неуместные архитектуры и изобретая велосипеды. Надо следить за тем, чтобы внешняя сложность не была больше внутренней.
  12. Когда при написании кода или проектировании архитектуры разработчик выбирает простое решение вместо правильного, он создаёт технический долг. По долгам придётся платить.
  13. Код других людей почти всегда кажется непонятным или криво написанным, не всегда причина в том, что код действительно криво написан. Иногда эти другие люди — это мы полгода назад.
  14. Иногда задача решается без изменения кода вовсе.
  15. Смелость менять то, что нужно менять, безразличие к тому, что изменить невозможно, и мудрость отличить одно от другого.
  16. Случается так, что тривиальное для разработчика бизнесу чрезвычайно полезно и ценно — это хорошая ситуация, не стоит от неё бежать.
  17. Редкая компания заинтересована в твоём росте: если бы её не устраивал твой текущий уровень, тебя бы не взяли.
  18. Конференции, митапы и прочее полезны в первую очередь людьми, которые пришли, и во вторую — докладами.
  19. Собеседование — это игра на двоих, не только компания смотрит на тебя, но и ты — на компанию.
  20. Мы приходим в профессию, потому что нам это интересно, но платят нам за пользу, которую мы приносим. Стоит почитать про cost center и profit center, и понимать, где ты находишься сейчас.
  21. Когда работаешь фрилансером, заказчик нанимает тебя ради скиллов, которых у него нет — он не может указать тебе на плохой код, а ошибки, которые ему видны, описывает своим языком.

Написать мысли насчёт, кхм, списка мыслей можно на [email protected] или в твиттере: я там @marinintim.