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

Мои главные принципы работы после 20 лет опыта в программировании

Время на прочтение 5 мин
Количество просмотров 57K
Всего голосов 46: ↑37 и ↓9 +28
Комментарии 73

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

"Делайте хорошо чтобы было хорошо" ))

Делайте хорошо. Не делайте плохо.

Плохо оно само получится ;)

для составления ТЗ клиентом тоже подойдет

Прочитал как "деплойте хорошее а плохое не деплойте"

Deloitte хорошо, а плохое не Deloitte?

ой, не знаю

"Делай хорошо — плохо само получится"

Делайте как надо, а как не надо - не делайте.

Нормально делай — нормально будет

Делай что должен и будь что будет

Кто минусул, вообще-то это латынь

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

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

Если автор под задачей имеет ввиду написание целой системы, то конечно да, тут он прав

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

Ну, в больших проектах это может и не прокатить.

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

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

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

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

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

Как раз это обычно написано в ТЗ :)
В тз обычно написано «за все хорошее и против всего плохого...». в ирл по результатам тз создается (или не создается, ибо нужно трясти, и тогда это остается в рабочем блокнотике) и, по возможности, согласуется рабочая документация, в которой, как правило, и описывается: что, зачем и почему. и пока фаза создания/согласования именно рабочего задания/документации не пройдена, за код лучше не садится. иными словами: пока вы не сможете объяснить другим, что именно вы хотите сделать, писать код вы не должны.

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

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

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


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

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

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

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

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

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

И у вас за все 23 года не было ошибок?

Таких, что получил ТЗ, выбрал инструмент, начал работу, а потом заказчик внёс изменения, и оказалось, что инструмент теперь не подходит? Нет, и я даже не слышал про такие случаи ни у кого. Гипотетически такая ситуация, конечно, может иметь место, но это явно не тот риск, который нужно закладывать в свою стратегию.
Ну хотя насчёт «нет», я чуть покривил душой, один раз был, в 2000 году. Когда заказчик попросил сайт и CMS под него (хотя такого слова тогда не было, но это сейчас называется CMS). Поскольку в 2000 году я был махровым джуном, и не знал ничего, кроме Delphi (да и Delphi так себе), я уточнил у заказчика, какие у них операционные системы. Заказчик сказал, что всё Windows, я облегчённо вздохнул, и написал CMS на том, что умел — на Delphi, соответственно, под IIS. Всё работало (к моему личному удивлению), всем всё понравилось, я получил свои деньги, а на следующей неделе контора объединилась с другой, и её ИТ-отдел напрочь отказался поднимать сервер под IIS, потому что винда-маздай, а линукс рулез. И то, проблему они решили, по-царски: выгрузили все HTML-ресурсы сайта в статические файлы, и потом правили их руками без CMS :)
Но это, скажем так, тот самый исключительный случай.

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

Пишите чистые функции, их проще объяснить. Любая функция, которая не является чистой, должна быть классом.

Добавили в функцию логирование и теперь пол проекта переписывать на классы?

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

Так в том и прикол не нужно там логирования. Пишите его в миддлварях, обзерверах ну или во враппере на худой конец. Типа single responsibility principle все дела..)

В теории оно конечно хорошо и правильно. А на практике вставить навсегда log.warning(...) в самые недра своего приложения иногда хочется. И это правда полезно и помогает в дебаге потом.

У любых правил должны быть исключения. Логи это исключение и расходимся.

Логи естественно асинхронные и неблокирующие. Мы закладываемся на то что в случае факапа одним из сайд эффектов которого была генерация огромного количества логов мы часть логов потеряем. Такие баги надо чинить ASAP. Есть хорошая вероятность того что сохранение всех логов не стоит тех расходов которые они несут.

НЛО прилетело и опубликовало эту надпись здесь

это очень дёшево и вопрос одного memcpy

Это в смысле как: дёшево/быстро/качественно - выберите любые два?)

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

Неспроста же 12factors заявили, десять вместо того чтобы пытаться решить нерешаемое - не майтесь дурью и пишите свои логи в stdout/stderr (синхронно, как же ещё больше), а там пусть разбираются.

НЛО прилетело и опубликовало эту надпись здесь

мы mmap или файл с логами и дописывали туда тем самым memcpy

синхронно

А вот подход «выплевывайте синхронно в stdout, наверху разберутся» точно бы не сработал.

Почему? stdout это обычный дескриптор. Просто он стандартный и доступен автоматически. mmap/memcpy с ним вполне работают (как минимум в линуксах), если при запуске приложения перенаправлен в файл ./a.out > log.txt. С терминалом конечно же нет.

Технически суть оптимизации была в замене fwrite на memcpy?

НЛО прилетело и опубликовало эту надпись здесь

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

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

НЛО прилетело и опубликовало эту надпись здесь

У любых правил должны быть исключения. Логи это исключение и расходимся.

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

тем, что логирование в норме не влияет на поведение других программ?


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

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

Исключительно надежное сохранение это минимум две географически разнесенные точки и коммит только после подтверждения записи в обе. Вы точно так сохраняете логи? Остальное это компромиссы.

Важные бизнес данные сохраняются именно так.

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

Думайте об этом процессе как о eventually consistent которое нарушается в случае какого-то факапа с генерацией неразумного объема логов.

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

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

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

Я не понимаю как запись в "других" потоках сделает ваше решение эффективнее по производительности, не говоря уже о надёжности и памяти? Если в "нормальном" состоянии вы не будете успевать записывать логи в файл, то через какое-то время упретесь в ограничение по памяти. Соответственно, количество затраченного времени на запись логов в файл должно быть меньше времени выполнения кода, который генерит эти логи. В этом же случае, используя асинхронную запись логов в файл драйвер вашего диска будет трансформировать эту операцию в последовательность команд, которые будут выполняется максимально эффективно для вашего физического устройства, используя его контроллер, кэш и прямой доступ к памяти, где хранятся ваши логи, не задействуя CPU, потоки вашего процесса и без переключения контекста выполнения (при нехватке ядер) . При всем при этом не будет расходоваться место в хипе вашего процесса для временного хранения вашего лога для записи его в отдельных потоках. Понятно что в некоторых случаях это не так, например игры, торговля на бирже роботами, где важна каждая наносекунда, но наверно там и логов много не будет, только исключительные ситуации, в которых можно и при тормозить на сотню наносекунд

У вас абстракции текут.

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

Из бизнес логики надо знать только одно: log.info(...) может вызвать IO с неизвестным временем выполнения или не может?

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

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

А что насчёт "преждевременная оптимизация"?

И насчёт рефакторинга ни слова!

10 лет опыта программирования на JavaScript. Нет опыта C# и .Net. Не увидел ничего про мобильную разработку (Kotlin, Objective C, Swift). Нет PHP и Python. Так себе авторитет…

Можно про ваш опыт почитать? Ах, у вас нет статей, как жаль.

НЛО прилетело и опубликовало эту надпись здесь

"Освободи свой разум. Стань бесформенным, словно вода." Брюс Ли.

Без примеров эти тезисы не стоят и гроша.

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

О как! Сатья без примеров, которую еще надо уметь понять... Может, автор не умеет хорошо излагать мысли? Допускаю, что программист он хороший. Но уж если взялся писать, то на каждый тезис нужно по два-три примера, а он поленился.

Любую статью надо понять и это тоже труд. Судя по комментам, многие поняли и без примеров. Еще по себе скажу, что моих примеров из моей жизни хватило, чтоб то, что написано, поименить к ним. Так что все-таки дело не в авторе, а в читателях. И да, не всякий автор подходит всякому читателю.

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

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

Пошли аналогии, я все.

Пункты 17 и 18 огонь

Привет. Хорошо. Так и буду делать. <b>)</b>

Высказаны 3 блока мыслей:
1. Делайте хорошо.
2. Плохо не делайте.
3. Мой уникальный опыт, примите на веру.

По большому количеству вроде-бы интересных пунктов хотелось бы расшифровки.
Возьмём для примера:

7. У всего кода есть жизненный цикл. Иногда код умирает в зачаточном
состоянии, ещё до производственной среды. Умейте отпустить. Различаются
четыре категории функционала, в которые нужно вкладывать время и силы.
Основа. Это как движок автомобиля. Без неё продукт не имеет смысла.
Необходимая часть. Похожа на запаску: редко используется, но определяет успех системы, когда требуется.
Дополнительные возможности. Это как подстаканник: ну есть и есть, хотя продукт вполне можно использовать и без него.
Уникальные свойства: почему стоит купить продукт у вас, а не у ваших конкурентов. Например, ваш автомобиль — лучший внедорожник.

Хотелось бы, чтобы автор как-то прокомментировал к чему эта классификация, чему она помогает / где вредна (про моторы и подстаканники на тех.ресурсе - вопрос отдельный).
С ходу кажется, что она нужна для построения диаграмм Ганта на момент начала проекта (когда неопределённости много уровень абстракции высок и планирование - искусство "правильно предсказать" а не технология "сменеджерить"), но никаких подсказок в этом пункте не вижу.

>Хотелось бы, чтобы автор как-то прокомментировал
Вы сейчас пытаетесь разговаривать с (гугло)переводчиком, у которого на 154 публикации 4 комментария.
Хорошему коду документация не нужна

Недокументированный — значит несуществующий функционал.

По-моему тут противоречие разве нет?

Если бы опыт можно было передать в виде текста, то люди давно перестали бы учиться на своих ошибках. Парадокс засовывания пальцев в розетку. Сколько не говори, пока не долбанет - не усваивается. Человек не "специально" это делает. Он так устроен. Это часть алгоритма познания.

Так что, те, кто понимают упомянутые в статье принципы, пришли к ним на собственном опыте. А те кто не понимают - и не поймут. Не потому что они "тупые". А просто "приложить" этот совет не к чему.

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

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

Помню у нас в колледже статистики, экономики и информационных технологий, в туалете, была надпись: "Писать на стенах туалета, увы друзья не мудрено, среди говна мы все поэты, среди поэтов мы говно". Я тоже пишу промышленный код с 1999, но меня удивляют такие статьи. Я не понимаю, а куда делся здравый смысл инженера-программиста, и что за сервис, научить программировать за неделю. Куда делась высшая математика, алгебра, логика, статистка из программирования. С 99 года применялись ли правила к программам автора, такие как, рекурсия, рефлексия, полиморфизм, абстракция, фактические и формальные параметры и пр.. Даже, если, в новом мире, айти, это всего лишь продажная девка бизнеса, то никто и никогда не исключает инженерную культуру и здравый смысл инженера-программиста, основанного, в первую очередь, на науке. И вам этого желаю. ;)

В целом хорошо, согласен, но вот такой пункт всегда удивлял:

"Выйдите из зоны комфорта. Учитесь каждый день. Учите других тому, чему научились."

Почему человек не должен чувствовать себя комфортно? Почему он должен учиться каждый день? Это же кратчайший путь к выгоранию

99 лет программирования. Вот мои принципы:

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

  2. Автоматическая клавиатура лучше, чем механическая.

  3. В Half-Life 2 в главе на автомобиле, когда доедете до разрушенного моста, нужно нажать Shift, чтобы машина ускорилась, иначе не допрыгните. Ох, сколько попыток это мне стоило...

Все правильно написано, только далеко от жизни. Программирую с 97 года. К сожалению, наиболее востребовано совсем другое: способность быстро разобраться в чужом недокументированном коде условно от 500К строк, с ужасной архитектурой и отсутствием возможности у кого-либо спросить. С крайне сумбурной терминологией в компании, и странным неймингом всего в коде. Потому как единственный программист недавно уволился. И, да, предыдущий программист также учился высокому чувству чистого кода, и до него также. В итоге: несколько СУБД разного типа (mongo, pg, kafka, и !!! redis как !!! брокер), несколько шин событий, странная логика изменений в БД, внешние ключи между БД и конфигами (совсем не бизнес-ключи, обычные int) и абсолютная связанность без зацепления. А, да, простите, - передача команд GET запросами без csrf, божественные классы, и жирные классы под 10К строк. Вот если бы кто-то написал инструкцию, как выживать в таких условиях, моей признательности не было бы границ.

Кратка инструкция: бегите оттуда, если есть возможность.

// Основано на личном опыте. И тут ещё с пол страницы можно вставить пространных рассуждений насчёт совпадения культуры написания кода и полезности работы для нервной системы и т.п. Но не нужно. Goto: Кратка инструкция

Так и сделал. :-)

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