image

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

Разработка ПО


Сначала спецификации, потом код


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

«Без требований или проекта программирование представляет собой искусство добавления багов в пустой текстовый файл» — Луис Срайгли

Иногда достаточно даже «краткой презентации» — не больше двух абзацев с описанием того, что делает ваше приложение.

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

Описывайте этапы как комментарии


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

Или ещё лучше: считайте каждый комментарий функцией, а затем напишите функцию, которая именно это и делает.

Gherkin поможет осознать ожидания


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

Модульные тесты — хорошо, интеграционные — ещё лучше


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

Тесты позволяют улучшать API


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

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

Делайте тесты, которые вы умеете запускать из командной строки


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

Будьте готовы отправить свой код в корзину


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

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

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

В хорошем языке есть интегрированные тесты


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

Думать на будущее означает тратить силы впустую


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

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

Решайте ту проблему, что есть сейчас. Затем решайте следующую. Потом следующую. Однажды вы подметите паттерн, возникающий на основе этих решений, и только потом вы найдёте ваше «универсальное решение».

Документация — это любовное послание себе в будущем


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

Документация функции — это её контракт


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

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

Если в описании функции есть «и», то это плохо


Функция должна делать только что-то одно. Когда пишете к ней документацию и видите, что добавили «и», то это означает, что функция делает что-то ещё. Разделите её на две функции и избавьтесь от «и».

Не используйте булевы значения в качестве параметров


При разработке функции может возникнуть соблазн добавить флаг. Не делайте этого.
Поясню на примере: допустим, у вас есть система передачи сообщений, и есть функция getUserMessages, возвращающая пользователю все сообщения. Но есть ситуация, в которой вам нужно возвращать либо краткую суть каждого сообщения (допустим, первый абзац), либо сообщение целиком. Поэтому вы добавляете параметр в виде флага или булева значения, который называете retrieveFullMessage.

Повторюсь, не делайте этого.

Потому что те, кто будут читать ваш код, увидят getUserMessage(userId, true) и будут недоумевать, что это вообще такое?

Или можете переименовать функцию getUserMessageSummaries и ввести getUserMessagesFull, или что-то подобное, но каждая функция будет просто вызывать исходную getUserMessage с true или false — зато интерфейс вовне вашего класса/модуля будет понятным.
Но не добавляйте в функции флаги или булевы параметры.

Опасайтесь изменений интерфейса


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

Можете создать новые функции и в документе или средствами кода пометить текущую функцию как нежелательную. И через несколько релизов можете наконец убить её.

Уродское решение: создать новые функции, пометить текущую как нежелательную и добавить sleep в начало функции, чтобы заставлять обновляться тех, кто использует старую функцию.

У хороших языков документация встроена


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

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

Язык — это нечто большее, чем просто язык


Вы пишете на языке программирования и заставляете вещи «работать». Но в нём есть далеко не только особые слова: в языке есть система сборки, система управления зависимостями, средства взаимодействия инструментов, библиотек и фреймворков, есть сообщество, есть способ взаимодействия с людьми.

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

Иногда лучше позволить приложению падать, чем ничего не делать


Хотя это звучит странно, но лучше не добавлять обработку ошибок, чем тихо ловить их и ничего не делать.

В Java есть печально распространённый паттерн:

try {
  something_that_can_raise_exception()
} catch (Exception ex) {
  System.out.println(ex);
}

Здесь с исключением ничего не делается, только выводится сообщение.

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

Если вы знаете, как обработать, сделайте это


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

Типы говорят о том, какие у вас данные


Память — это всего лишь последовательность байтов. Байты — это просто числа от 0 до 255. Что эти числа означают, описано в системе типов языка.

К примеру, в С тип символа (char type) со значением 65 наверняка будет буквой «А», а int со значением 65 будет числом 65.

Помните об этом, работая со своими данными.

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

console.log(true+true === 2);
> true
console.log(true === 1);

> false

Если у ваших данных есть схема, храните их в виде структуры


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

Осознайте и держитесь подальше от карго-культа


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

«Если БольшаяКомпания хранит данные таким образом, то и мы можем».

«Если это использует БольшаяКомпания, то это хорошо».

«Правильный инструмент для задачи» — это способ навязать своё мнение


Фраза «правильный инструмент для задачи» должна означать, что есть правильный и неправильный инструмент для чего-либо. Например, использование определённого языка или фреймворка вместо текущего языка или фреймворка.

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

«Правильный инструмент» очевиднее, чем вы думаете


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

О чём вы забываете: ваша команда специализируется в С. Все знают С, а не Perl.

Конечно, если это маленький проектик «на коленке», то можно и на Perl. А если проект важен для компании, лучше писать его на С.

P.S.: Ваш героический проект (подробнее об этом ниже) из-за этого может провалиться.

Не влезайте в то, что находится вне вашего проекта


Иногда вместо того, чтобы использовать подходящие инструменты для расширения, люди начинают менять внешние библиотеки и фреймворки. Например, вносят изменения прямо в WordPress или Django.

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

Потоки данных побеждают паттерны


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

Паттерны проектирования используются для описания решений, а не для их поиска


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

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

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

Научитесь основам функционального программирования


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

Когнитивные усилия — враг читабельности


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

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

Магическое число семь плюс-минус два


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

Если у вас есть функция, которая вызывает функцию, которая вызывает функцию, которая вызывает функцию, которая вызывает функцию, которая вызывает функцию, то это просто ад для читающего ваш код.

Вы только вдумайтесь: я получу результат выполнения этой функции, передам его второй функции, получу её результат, передам третьей, и т.д.

Более того, сегодня психологи уже чаще говорят о магическом числе ЧЕТЫРЕ, а не семь.
Мыслите в категории «композиции функций» (например, «я вызову эту функцию, потом ту, затем вон ту...»), а не в категории «вызова функций» (например, «эта функция вызовет ту, она вызовет вон ту...»).

Сокращения хороши, но только в краткосрочной перспективе


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

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

Не поддавайтесь соблазну «лёгкости»


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

Вы знаете, как работает ваша система сборки? Если придётся запускать её без IDE, вы сможете это сделать?

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

Интересуйтесь тем, что происходит под капотом.

ВСЕГДА используйте в датах часовые пояса


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

ВСЕГДА используйте UTF-8


С кодировками у вас будут те же проблемы, что и с датами. Поэтому всегда преобразуйте строковые значения в UTF-8, сохраняйте их в базах данных в UTF-8, возвращайте из своих API в UTF-8.

Можете преобразовывать в любую другую кодировку, но в войне кодировок победила UTF-8, так что проще всего придерживаться её.

Начните по-глупому


Один из способов уйти от IDE, это «начать по-глупому»: просто возьмите компилятор, ЛЮБОЙ редактор с подсветкой кода и — программируйте, собирайте, запускайте.

Да, это не легко. Но когда потом вы воспользуетесь каким-нибудь IDE, то будете думать о кнопках всего лишь «Да, это запускает вон то». Именно это и делают IDE.

Логи предназначены для событий, а не для пользовательского интерфейса


Я долгое время с помощью логов показывал пользователям, что происходит с приложением. Ну, вы знаете, потому что гораздо проще использовать одну вещь, чем две.

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

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

Отладчики переоценены


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

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

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

Всегда используйте систему версионирования


«Это просто моё дурацкое приложение, с помощью которого я хочу кое-чему научиться» — это не оправдывает отсутствие системы версионирования.

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

По одному изменению в коммите


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

Придерживайтесь принципа «по одному изменению в коммите». И под изменением я подразумеваю изменение в одном файле. Если нужно менять три файла, то коммитьте эти файлы вместе. Спросите себя: «если я откачу это изменение, что должно исчезнуть?»

«git add -p» поможет вам при избытке изменений


Это касается только Git. Он позволяет с помощью параметра "-p" объединять файлы частично, так что вы можете выбирать только связанные друг с другом изменения, оставляя другие для нового коммита.

Структурируйте проекты по данным или типу, а не по функциональности


В большинстве проектов используется такая структура:

.
+-- IncomingModels
|   +-- DataTypeInterface
|   +-- DataType1
|   +-- DataType2
|   +-- DataType3
+-- Filters
|   +-- FilterInterface
|   +-- FilterValidDataType2
+-- Processors
|   +-- ProcessorInterface
|   +-- ConvertDataType1ToDto1
|   +-- ConvertDataType2ToDto2
+-- OutgoingModels
    +-- DtoInterface
    +-- Dto1
    +-- Dto2

То есть данные структурированы по функциональности (все входные модели лежат в одной директории или пакете, все фильтры в другой директории или пакете, и т.д.).

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

.
+-- Base
|   +-- IncomingModels
|   |   +-- DataTypeInterface
|   +-- Filters
|   |   +-- FilterInterface
|   +-- Processors
|   |   +-- ProcessorInterface
|   +-- OutgoingModels
|       +-- DtoInterface
+-- Data1
|   +-- IncomingModels
|   |   +-- DataType1
|   +-- Processors
|   |   +-- ConvertDataType1ToDto1
|   +-- OutgoingModels
|       +-- Dto1
...

Теперь можно сделать модуль, который работает только с Data1, другой модуль — работающий только с Data2, и т.д. А затем можете разделить их на изолированные модули.

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

Делайте библиотеки


Я часто видел, как разработчики либо создают мега-репозитории с разными проектами, либо держат разные ветки, не для того, чтобы они были временной средой для последующего присоединения к основной части, а просто для дробления проекта на более мелкие части (говоря о разбиении на модули, представьте, что вместо сборки нового проекта, который повторно использует тип Data1, я использую ветку с совершенно другой основной функцией и типом Data3).

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

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

Научитесь мониторить


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

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

Дело в том, что без последующего мониторинга довольно странно пытаться выяснить, насколько «здорова» система. Проверка здоровья в стиле «Отвечает ли на запросы» больше не подходит.
Раннее добавление мониторинга поможет понять, как ведёт себя система.

Пользуйтесь конфигурационными файлами


Представьте: вы написали функцию, которой нужно передать значение, чтобы она начала обрабатывать (скажем, ID аккаунта в Твиттере). Но потом это нужно сделать уже с двумя значениями, и вы просто снова вызываете функцию с другим значением.

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

Опции для командной строки выглядят странно, но они полезны


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

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

Не просто композиции функций, а композиции приложений


В Unix используется такая концепция: «приложения, которые делают что-то одно, и делают это хорошо».

Я говорил, что вы можете использовать одно приложение с двумя конфигурационными файлами. А если вам нужны результаты из обоих приложений? Тогда можно написать приложение, которое считывает результаты второго, и объединяет всё в общий результат.

Даже при использовании композиции приложений, начните по-глупому


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

Оптимизации оставьте компиляторам


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

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

О чём вам нужно думать, так это о более качественном проекте для вашего кода, о том, как улучшить текущий код. Он нужен для того, чтобы его читали люди. ВСЕГДА. А оптимизациями занимаются компиляторы. Так что вместо использования более коротких слов найдите более толковый способ объяснить в коде, что вы хотите сделать.

Ленивое вычисление


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

В команде и на работе


Ревью кода не предназначено для проверки стиля


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

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

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


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

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

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

Соблюдайте стиль кода


Если в вашем проекте есть определённый стиль кода, вы должны его соблюдать. Иногда это бывает не очевидно («этот класс должен быть в единственном числе или во множественном?»), но всячески старайтесь это делать.

… если это не стиль Google


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

Для C/C++ есть только один стиль кода — K&R


Снова исключительно личное мнение. Все остальные стили ОШИБОЧНЫ :)

Для Python есть только один стиль кода — PEP8


Большая часть сообщества пишет в стиле PEP8. Соблюдайте его, и ваш код легко вольётся в существующую экосистему.

Явное лучше неявного


Знаете, какое самое худшее имя для функции? sleep().

На сколько нужно заснуть? Это в секундах или миллисекундах?

Явно указывайте, что вам нужно. Варианты sleepForSecs и sleepForMs не идеальны, но это лучше, чем sleep.

Помните об этом, когда пишете свой интерфейс для командной строки или конфигурационный файл.

Я могу сюда скопировать всю книгу «Zen of Python», но стараюсь сосредоточиться на личном опыте.

Компании ищут специалистов, но универсалов держат дольше


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

«Не стоит изучать язык, который не влияет на ваше представление о программировании» — Алан Перлис.

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

Я узнал, как в Java работают дженерики, когда писал код на Rust. Я понял, как в Spring выполняется внедрение зависимостей, когда прочитал об этом в С++.

Думайте о пользователях


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

Получив данные, не забудьте защитить их от злоумышленников.

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


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

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

Сохраняйте информацию о «тупых ошибках, на исправление которых у меня ушло больше часа»


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

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

Если это не работает на вашем компьютере, у вас проблема


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

И это действительно снижает продуктивность.

Если ваша система будет работать в специализированном окружении (и я включаю в это понятие «облака»), то подумайте, как можно абстрагировать всё, что вы используете. Например, если вы задействуете AWS SQS (то есть очередь), поищите библиотеку, позволяющую абстрагировать способ работы очереди, чтобы вы могли запустить систему на вашем компьютере с RabbitMQ.

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

Личное


Когда нужно остановиться, пора останавливаться


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

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

Кодекс поведения защищает вас, а не их


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

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

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

Научитесь отказывать


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

Однажды мне пришлось сказать нашему техническому директору: «Ладно, я сделаю, но хочу отметить, что не согласен с тем, что мы делаем». В результате приложение запретили именно за то, что мы делали.

Вы отвечаете за использование вашего кода.


Это трудно. Очень-очень трудно. В этом заключается разница между «свободой» и «ответственностью».

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

Не говорите, что всё готово, если это не так


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

Не делайте этого.

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

Вы познаете себя на горьком опыте


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

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

Люди чувствуют недовольство и раздражение из-за кода или архитектуры, потому что им не всё равно


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

«Ага, тебе не нравится это раскритикованное решение, потому что тебе не всё равно» — это были одни из лучших слов, которые я услышал в свой адрес.

Учитесь на своих неприятностях


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

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

Обращайте внимание на то, как на вас реагируют люди


У меня лицо «сердитого человека».

Иногда я о чём-то спрашиваю, а люди слегка отступают, словно я говорю им, что их решение неверное. Поэтому мне приходится добавлять: «я не хочу сказать, что это неправильно, просто мне интересно».

Это может помочь вам уберечься от неприятностей.

Учитесь распознавать токсичных людей и держитесь от них подальше


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

Вы не представляете, как такое отношение будет вас угнетать.

Опасайтесь «микроагрессий»


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

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

Лучше держаться от такого подальше и контактировать как можно меньше.

Нет, я не думаю, что они могут «исправиться»


Личное мнение. Кто-то скажет: «Может, если ты поговоришь с этими людьми, они перестанут так делать?»

Я считаю, что не перестанут. Для них это стало естественным поведением, и чаще всего тебе скажут, что ты ошибаешься (например, потому что не понимаешь, что они шутят).

Токсичных и микроагрессоров можно исправить, только если они — это ВЫ


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

… в основном потому, что услышав это от кого-то другого, вы можете почувствовать, словно «это они против меня!».

Героические проекты: однажды вам придётся такое сделать


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

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

Иногда это доказывает, что вы ошибаетесь.

Но в любом случае вы что-то для себя извлечёте.

Не путайте «героический проект» с «синдромом героя»


Я встречал такое минимум дважды: кто-то заявляет, что пока его нет рядом, ничего не работает, или что он не нуждается в помощи.

Это «синдром героя» — человек считает, что только он способен решать все проблемы.

Не будьте такими.

Осознавайте, когда нужно уйти


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

Кто-то из коллег постоянно вас микроатакует.

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

Третий всегда бухтит, что стоит ему отойти, как всё перестаёт работать.

Значит, пришла пора рассылать резюме, вне зависимости от того, хорошо ли вам платят и крут ли проект.

… если только вы не хотите к сорока превратиться в постоянно недовольного и раздражённого типа.

Мир IT очень тесен


Он и правда очень тесен.

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

И за это время вы встретите много других айтишников.

И они будут рассказывать о себе.

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

Бумажные блокноты действительно полезны


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

Trello — это круто и всё такое, самоклеящиеся записки лучше


Ничто так не иллюстрирует фразу «я действительно занят, но организован», как куча приклеенных листочков на вашем столе.

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


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

Создайте блог. Пишите о своих дебильных решениях. Они всё ещё лучше, чем чьи-то ещё.

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

Покажите свой рост.

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

… только отключите комментарии


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

Отключите комментарии. Не позвольте другим вас остановить.

Публикуйте ваши дурацкие решения в сети


Не надо держать Github только для «классных, почти идеальных» проектов. Вы можете показать, что когда-то были новичком.

Вы всегда можете вернуться и улучшить код.

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

Заведите список «того, что я не знаю»


У Ричарда Фейнмана, известного физика, был блокнот, озаглавленный «То, чего я не знаю».

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

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


  1. saipr
    20.06.2019 12:34

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

    А представляете, на заре программирования в 60-е, да и в начале 70-х было четкое разделение на алгоритмистов и кодировщиков. Первые четко описавали алгориртм, который требовалось запрограммировать. И не просто описывал, а представлял в виде блок-схемы со всеми переменными и разветвлениями. И кодировщику оставалось четко следовать этой блок-схеме и переводить ее на соответствующий язык (ассемблер, автокод, Алгол, Фортран, Алмо и т.д.). Порой кодировщик и понятия не имел для чего нужна программа.
    Но времена изменились. В первую очередь изменились языки. И Сегодня программист и алгоритмист, и кодировщик, и предметник и т.д. и т.п. И у него часто возникает вопрос


    что делать дальше?


    1. slovak
      20.06.2019 14:20

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


    1. Alcpp
      21.06.2019 01:48

      Так вот зачем мы учили и рисовали блок-схемы 20 лет назад.

      Приятно наконец узнать, что это потому, что 50 лет назад было такое разделение.


      1. saipr
        21.06.2019 09:48
        +2

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


      1. Alcpp
        21.06.2019 22:58

        Интересно, а современные студенты сейчас изучают воплощение алгоритмов в блок-схемах?


        1. mayorovp
          22.06.2019 13:51

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


    1. Gorthauer87
      21.06.2019 14:06
      +2

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


      1. saipr
        21.06.2019 14:22
        -1

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


  1. IgorPie
    20.06.2019 13:14

    Перевод материала Капитана Очевидность, имхо.


    1. cubit
      20.06.2019 14:32

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


    1. Aingis
      21.06.2019 12:52

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


      1. IgorPie
        22.06.2019 20:02

        Потому, что и так сойдет, чаще всего. Некогда мусолить, надо дальше бежать, и т.п.


  1. Fedorkov
    20.06.2019 15:02

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

    Не используйте булевы значения в качестве параметров.… можете переименовать функцию getUserMessageSummaries и ввести getUserMessagesFull, или что-то подобное, но каждая функция будет просто вызывать исходную getUserMessage с true или false — зато интерфейс вовне вашего класса/модуля будет понятным.
    Для этого существуют enum-ы.

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

    ВСЕГДА используйте в датах часовые пояса
    ВСЕГДА используйте UTC, кроме пользовательского ввода-вывода. Если с часовыми поясами работать всё-таки придётся, убедитесь, что в используемой библиотеке достаточно мало багов (от стандартных библиотек часто приходится отказываться).

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

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

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

    Кто-то скажет: «Может, если ты поговоришь с этими людьми, они перестанут так делать?» Я считаю, что не перестанут.
    Всегда лучше выговориться (без наездов), чем держать в себе недомолвки. Если человек не исправляется, можно ненавязчиво привлечь других людей. Хуже точно не будет.

    С большинством остальных пунктов согласен.


    1. Rhombus
      21.06.2019 13:46
      +2

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

      А иногда наоборот лучше заменить хеш-таблицу на массив ;)


    1. yarick123
      22.06.2019 00:36
      +2

      Думать на будущее означает тратить силы впустую

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


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

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

      Не используйте булевы значения в качестве параметров.…

      Для этого существуют enum-ы.


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

      Я встречал данный антипаттерн в ситуациях, когда поведение процедуры следовало изменить при определённых внешних условиях. Тогда список параметров расширялся, добавлялся N+1-ый параметр типа boolean со значением по умолчанию false. Этот параметр «включал» новое поведение. Таким образом, считалось, что весь старый код продолжал работать как раньше, а там, где требовалась изменённое поведение, вызывалась процедура с этим параметром true. Мне, например, весьма часто не было понятно, что-же этот последний true обозначает…

      А так — да, enum-ы — хорошая штука.

      «Правильный инструмент для задачи» — это способ навязать своё мнение

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


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

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

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

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

      ВСЕГДА используйте в датах часовые пояса

      ВСЕГДА используйте UTC, кроме пользовательского ввода-вывода. Если с часовыми поясами работать всё-таки придётся, убедитесь, что в используемой библиотеке достаточно мало багов (от стандартных библиотек часто приходится отказываться).


      «Дата с часовым поясом» — это больше, чем UTC. По ней можно сказать, например, когда у человека день, а когда ночь. Стоит ли ждать от него скорого ответа. Стоит ли ему сейчас звонить…

      Я наблюдал и участвовал в задачах перевода систем с локального времени без часового пояса на UTC и иногда потом на время с часовым поясом. В другую сторону перехода делать, по крайней мере в моём мире, никогда не требовалось. А как бы было хорошо, если бы c самого начала время просто было с часовым поясом!

      Поэтому Ваш совет «ВСЕГДА используйте UTC» я рассматриваю как шаг назад по сравнению с тем, что предлагает автор. Да, если используемые библиотеки с часовыми поясами работать не умеют, ничего не остаётся, как взять только UTC. Но это для меня безысходность, а не практика, которую я бы всем предлагал.

      Отладчики переоценены

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


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

      Речь-то идёт о том, что будет делать разработчик, когда воспользоваться отладчиком нет возможности. Тогда-то и будет польза в умении работать без отладчика, в грамотном логировании,… etc.

      Оптимизации оставьте компиляторам

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


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

      Я бы сказал, что улучшениями алгоритмов стоит заниматься, как тo: замена используемых структур данных на более подходящие для Ваших условий, добавление кэширования,… etc. Впрочем, именно так я и понимаю слова автора: «О чём вам нужно думать, так это… о том, как улучшить текущий код.».

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

      Соответственно, зная об этих оптимизациях, я стараюсь писать красивый хороший понятный код.

      Кодекс поведения защищает вас, а не их

      Понял фразу, только когда прочитал в оригинале. По-русски говорят «не лезьте в чужой монастырь со своими правилами».


      Для меня привычнее «в чужой монастырь со своим уставом не лезут».

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

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

      Кто-то скажет: «Может, если ты поговоришь с этими людьми, они перестанут так делать?» Я считаю, что не перестанут.

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


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

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

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

      Уф, как-то длинно получилось. Просто за душу взяло… :)


      1. Fedorkov
        22.06.2019 03:39
        +1

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

        Мне, например, весьма часто не было понятно, что-же этот последний true обозначает…
        Именно поэтому нужен enum, который в нашем случае будет играть роль именованного типизованного bool-а.

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

        «Дата с часовым поясом» — это больше, чем UTC. По ней можно сказать, например, когда у человека день, а когда ночь. Стоит ли ждать от него скорого ответа.
        А если он — топ-менеджер, который полжизни проводит в аэропортах? Всегда найдётся частный случай, в котором фундаментальные проблемы часовых поясов будут порождать баги на уровне требований; и чем реже вы мешаете время с часовыми поясами, тем меньше будет багов.

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

        то, что вы назвали «оптимизацией» для меня является процессом исправления ошибки.
        Если медленная работа не противоречит требованиям, то мы тут начнём спорить о субъективных (архитектурных, стилистических) ошибках. Всё-таки оптимизация — вполне чёткое и вполне подходящее здесь понятие.

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


        1. yarick123
          22.06.2019 21:54

          Я не согласен с утверждением автора, что отладчики «просто не оказывают той помощи, которой от них многие ждут»

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


  1. worldmind
    20.06.2019 15:16

    Весьма неплохо в целом. По последним пунктам сразу вспомнилась книга Саттона «Не работайте с мудаками»


    1. vvbob
      21.06.2019 08:39
      +2

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


      1. worldmind
        21.06.2019 08:43

        Честно говоря, прямо такого мудака как описано у Саттона я встречал только на одной своей работе и то, он был далёк от ИТ и мы с ним перескались исключительно редко, буквально пару раз. Это не значит, что с все остальные были отличными коллегами, но такой степени мудачности я больше ни у кого не припомнил.


        1. vvbob
          21.06.2019 09:11

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


  1. terrier
    20.06.2019 15:35

    Явно указывайте, что вам нужно. Варианты sleepForSecs и sleepForMs не идеальны, но это лучше, чем sleep.

    Классная идея — включать тип аргументов в название функций. Сразу видна забота о тех, кто программирует в nano, ed'е и на бумажке. К сожалению, не раскрыта тема функций strcpyStrConstStr и timeTimeT.


    1. v2kxyz
      20.06.2019 15:47

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


      1. terrier
        20.06.2019 15:55

        Там не тип включается, а описание того, что делает функция.

        Хотите сказать, что функции sleepForSecs и sleepForMs делают что-то разное, а не отличаются только типом аргумента?
        (и это даже не говоря о том, что название слипФорСекс неудачное как ни посмотри)


        1. v2kxyz
          20.06.2019 16:13

          Да. Очевидно, что спатьСекунды и спатьМиллисекунды. Пример немного надуманный, но посыл вроде понятен.
          Сколько усилий вам понадобится, чтобы понять какое количество времени код будет «спать» в случае чтения:
          sleep(7);
          А сколько в случае?
          sleepForSeconds(7);
          Неплохой альтернативой в подобных случаях может быть:
          sleep(7, units::seconds);

          (и это даже не говоря о том, что название слипФорСекс неудачное как ни посмотри)

          Почему неудачное?


          1. terrier
            20.06.2019 16:48

            Очевидно, что спатьСекунды и спатьМиллисекунды.

            То есть вы не считаете, что эти две функции делают одно и то же? Интересное мнение. Не особо распространенное.

            Сколько усилий вам понадобится, чтобы понять какое количество времени код будет «спать» в случае чтения:
            sleep(7);

            Нужно будет посмотреть сигнатуру этой функции, если я ее не знаю. Но дело в том, что эта проблема решается не дописыванием типа аргументов в название функции (и созданием кучи функций sleepForSecs, sleepForMs, sleepForYears ), а передачей в функцию sleep объекта типа Time/Duration/Chrono и т.д. Собственно, во всех разумных современных языках и библиотеках (… которые я видел ), так и сделано.

            Почему неудачное?

            Скрытый текст
            Вот буквально недавно столкнулся с Enterprise Quality фреймворком, который ходит по коду, ищет в идентификаторах вхождения буквосочетаний «sex/fuck/vagina/cunt» во всех вариантах написания и сигнализирует об этом. Говорят, его написали после того как одна крупнейшая корпорация выпустила публичную апишку с классом с именем типа BitChangerEngine, а потом была вынуждена резко его депрекейтить. Как говорят у нас в деревне: The struggle is real!


            1. v2kxyz
              20.06.2019 17:32
              +1

              То есть вы не считаете, что эти две функции делают одно и то же? Интересное мнение. Не особо распространенное.

              В учебно-показательном примере — да, они разные, примерно как quickSort и mergeSort(ну вот мне тоже более реальные примеры в голову не идут). Еще раз, этот пункт про полноту наименования функций/методов/классов/переменных.
              Нужно будет посмотреть сигнатуру этой функции, если я ее не знаю. Но дело в том, что эта проблема решается не дописыванием типа аргументов в название функции (и созданием кучи функций sleepForSecs, sleepForMs, sleepForYears ), а передачей в функцию sleep объекта типа Time/Duration/Chrono и т.д. Собственно, во всех разумных современных языках и библиотеках (… которые я видел ), так и сделано.

              Да не тип туда дописывается и дополнительная(и часто необходимая) информация о действии, которая функция совершает.
              Был бы тип, было бы название функции sleepTime — действительно странное название.
              Есть вот эта злосчастная sleep в UNIX(принимает секунды) и в Windows(принимает миллисекунды), лучше бы они назывались соответствующе, раз в С нет возможности создавать собственные типы Time/Duration/Chrono.


            1. Jeka178RUS
              21.06.2019 14:04

              По мне так вразы проще выбрать нужную функцию по имени чем передавать туда какую-нибудь шаблонную хрень типа std::chrono::duration с каким нибудь вызовом std::chrono::duration_cast<бла-бла>

              А что не так с BitChangerEngine?


              1. MicroCephalis
                21.06.2019 14:11
                +1

                Тоже на некоторое время завис, но вроде понял: видимо, дело в том, что там можно прочесть «bitch».


                1. Fedorkov
                  21.06.2019 15:21
                  +2

                  Тогда надо запретить слова assemble, assert, assist и assess.


                  1. ainoneko
                    21.06.2019 21:48

                    А Bit banging ещё не запретили?


              1. terrier
                21.06.2019 14:11
                +1

                А что не так с BitChangerEngine?

                BitchAngerEngine


          1. vladkorotnev
            21.06.2019 04:10

            В этом плане по синтаксису имхо рулит обжектив-си, где можно написать, к примеру, [MYSleeper sleepForSeconds: 10.0f]; [MYSleeper sleepForMilliseconds: 1000.0f];, хотя там, опять же, есть общепринятый тип данных NSTimeInterval, равный секунде и являющийся при этом float :-)


          1. botyaslonim
            21.06.2019 11:14
            +1

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


        1. kzhyg
          20.06.2019 18:43

          _delay_ms
          _delay_us


          1. COKPOWEHEU
            21.06.2019 14:27

            Тоже вспомнил такие названия из avr-gcc


            1. kzhyg
              21.06.2019 14:37

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


              1. COKPOWEHEU
                21.06.2019 14:42

                Что ж тут зубодробительного? Разве что подчеркивание в начале лишнее, отдает приватной библиотечной функцией.


                1. kzhyg
                  21.06.2019 14:56

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


                  1. COKPOWEHEU
                    21.06.2019 16:00

                    смотря где. Бывают ситуации, требующие высокой скорости и прерывать их другими задачами нет смысла. Хотя бы SPI: что программный, что аппаратный на максимальной скорости занимают десяток тактов. Программа просто не успеет переключиться чтобы сделать еще что-то в этом огрызке времени.
                    Или наоборот, есть длинная и развесистая задача в основном цикле, а все остальное распихано по прерываниям. Ну и смысл городить недо-ОС, когда задача всего одна.
                    В общем, как везде: есть инструмент. Есть люди, применяющие его к месту. А есть обезьяны, применяющие везде. Но инструмент-то в этом не виноват.


                    1. kzhyg
                      21.06.2019 16:43

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


                      1. COKPOWEHEU
                        21.06.2019 17:03

                        делеи не для точных таймингов в любом случае. Это скорее из серии «выждать 10 мс пока питание стабилизируется», «выждать 100 мкс когда дисплей прожует предыдущий байт»
                        Где нужны точные задержки, там надо как минимум прерывания запрещать. А лучше, конечно, использовать человеческие методы.


        1. ainoneko
          21.06.2019 07:57

          а не отличаются только типом аргумента?
          Без дополнительной информации (из документации, если она не устарела) не очевидно, что они отличаются и типом аргумента.
          Обе могут внезапно принимать целые (или вещественные).
          Или и те, и другие. Или принимать вещественные и округлять. И считать, что 0, полученный из 0.1 означает не нулевую задержку, а наоборот: «пропустить всех остальных вперёд».
          название слипФорСекс неудачное как ни посмотри)
          слипФорМиз тоже могут посчитать сексистским. ?\_(?)_/?


      1. GCU
        20.06.2019 16:01
        +3

        Если бы аргумент был объектом класса «единицы времени», то всё и так было бы понятно — секунды это или милисекунды :).


        1. v2kxyz
          20.06.2019 16:27

          Согласен, но от языка много зависит, если память не изменяет(очень давно не писал), то в C++ вполне допустимо написать такое:

          class Seconds {
          Seconds(int seconds){}
          };
          void sleep(Seconds sec){}
          sleep(7);
          

          А еще всякие динамически типизированные языки есть или чистый C без всяких классов.
          Да и еще раз — пример надуманный, но неужели у вас ни разу не возникало чувство недостаточности в имени класса/функции/переменной?


          1. terrier
            20.06.2019 16:56
            +1

            Не, недопустимо. Могут появиться травмы лица за конструктор с одним параметром и без explicit ( что как раз и предотвращает эту проблему ).


            1. v2kxyz
              20.06.2019 17:57
              +1

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


          1. FoxCanFly
            21.06.2019 13:15
            +6

            В C++ давно уже единственным нормальным вариантом будет

            std::this_thread::sleep_for(7s);


            1. netch80
              22.06.2019 10:01

              Это начиная с 14-го.
              У нас, например, пока разрешён только 11-й, поэтому

              std::this_thread::sleep_for(std::chrono::seconds(7));


        1. androidovshchik
          20.06.2019 16:59

          Или комментарии

          /**
           * @param time in milliseconds 
          */
          fun sleep(time: Long)
          


    1. COKPOWEHEU
      21.06.2019 14:40
      +1

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

      #define TIMEOUT 2
      ). В каких он единицах? Секунды, микросекунды, тики таймера? А вот если явно указать человеко-читемую единицу
      #define TIMEOUT_S 2
      , сразу ясно, что в секундах. Потом, для машинного представления, можно добавить формулу, по которой препроцессор переведет в тики или в чем там удобно. Но настройки должны быть человеко-читаемы.
      Еще хуже с физическими величинами. Переменная
      double channel_len;
      в каких единицах? Но стоит добавить суффикс, и неоднозначность исчезает:
      double channel_len_mm;
      . А совсем хорошо непосредственно перед наложением переменных на формулу привести их к единой системе единиц (для научных формул — СИ). Разумеется, поименовав в соответствии с размерностью. Добавляется перекладывание переменных, зато меньше риск ошибки.
      И в этом смысле удачно сделали разработчики Atmel со своими _delay_ms, _delay_us или, если кому ближе usleep. Гораздо нагляднее всяких Sleep, delay и т.п.


  1. sheknitrtch
    20.06.2019 16:55
    +1

    Спасибо за полезные советы. Опытным программистам они должны быть в большинстве своём очевидными.
    По поводу совета «Не используйте булевы значения в качестве параметров» мне вспомнилось правило «Язык определяет сознание». В Java код

    getUserMessage(userId, true)

    действительно выглядит неинформативно, но в Python можно писать:
    getUserMessage(userId, includeBody=True)

    A в Smalltalk синтаксис предполагает многословное имя метода:
    getUserMessage: userId.    //Метод с один аргументом
    getUserMessage: userId includeBody: True.    //Метод с двумя аргументами
    


    1. netch80
      22.06.2019 10:00

      Ещё это в Swift повторили, внешние имена аргументов много где обязательны.


  1. kzhyg
    20.06.2019 18:50
    +1

    > Магическое число семь
    Я бы сказал «два», всё, что выше, работает только в дурацких случаях вроде проброса списка аргументов.
    > когда ваш код находится в эксплуатации, вы не можете запускать свой любимый отладчик. Чёрт, да вы даже не можете запускать свой любимый IDE.
    Неоднократно так делал, когда больше ничего не помогало. Та же Java позволяет приаттачить отладчик к удалённой машине.


    1. Rhombus
      20.06.2019 19:41

      Аттачить-то можно, только если код многопоточный, то не факт, что это поможет.
      А иногда и аттачить нельзя из-за политик безопасности.


      1. kzhyg
        20.06.2019 19:47

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


    1. pesh1983
      23.06.2019 23:23
      +1

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


      1. kzhyg
        23.06.2019 23:30

        Несколько сотен JVM вполне вытянет, а клиент и так ОЧЕНЬ несчастен, раз дошло до отладки)


        1. pesh1983
          24.06.2019 08:58

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


          1. mayorovp
            24.06.2019 09:12

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


            1. pesh1983
              24.06.2019 09:16

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


              1. mayorovp
                24.06.2019 09:48
                -1

                Лучше всего дорабатывать процессы тестирования, чтобы ошибки до прода не доходили.


                А логи и метрики обо всем рассказать не могут.


  1. Ogoun
    20.06.2019 20:36

    > Я узнал, как в Java работают дженерики, когда писал код на Rust. Я понял, как в Spring выполняется внедрение зависимостей, когда прочитал об этом в С++.

    Из своего опыта, лучше всего понимается как и почему написано что-то, если попробовать написать это с нуля (логгер, сериализатор, мапперы, сетевое взаимодействие и т.д.). Становится понятным почему авторы сделали или не сделали именно так.


  1. AllexIn
    20.06.2019 21:36

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

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

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

    waaaaaaaaaat????
    Тем более что очень часто по названию переданных аргументов всё равно нельзя сказать что там должно быть по сути.
    Может 30 лет назад это было актуально, но сейчас IDE легко и просто рассказывает что там за переменная и для чего она. В целом догадываться о том, что значат аргументы по названиям переданных туда переменных — спорное удовольствие.

    Дальше тоже спорные высказывания, но комментировать всё — еще одна статья получится. Тоже спорная.


    1. Gambits
      20.06.2019 22:48

      Спасибо за ваш опыт! Многое из написанного — очень полезно!


    1. MicroCephalis
      21.06.2019 14:15

      сейчас IDE легко и просто рассказывает что там за переменная и для чего она

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


      1. AllexIn
        21.06.2019 15:13

        В VIM нет проблем с просмотров аргументов у функции.
        А в блокноте и на листочке именованные аргументы всё равно не помогут.


    1. mayorovp
      21.06.2019 16:17
      +1

      IDE-то рассказывают, но иногда код смотрят вообще в браузере, без всяких IDE...


    1. bogolt
      22.06.2019 14:32
      -1

      Вспоминается Qt
      setVisible(bool)
      и show(), hide()
      очевидно что последниее более читаемые, но если у нас состояние динамическое setVisible(новоеСостояние) намного удобнее чем городить ифы.


  1. eternal_why
    20.06.2019 22:17

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

    Иногда вот пишешь, пишешь, и тут звоночек:

    Если в описании функции есть «и», то это плохо

    Лады, конкретно здесь и сейчас нас спасёт булев параметр, но:
    Не используйте булевы значения в качестве параметров

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

    Да, для меня это тоже ад, но блин, где остановиться-то? Кто как такое сам для себя решает?.. Понятно, что у каждого будет как-то «по ситуации», но, быть может, существуют какие-нибудь наработанные/эмпирические правила/рекомендации?..

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


    1. vvbob
      21.06.2019 09:01
      +2

      У функций должны отсутствовать побочные эффекты, она должна делать только что-то одно, но делать это максимально хорошо. Если она написана именно так, то при ее описании не возникает желания использовать «и», и тем более перечисление побочных эффектов.
      Вкрячивание булевых параметров, которые кардинально меняют поведение функции — это такой кривой костыль, автор об этом. Само собой у любого эмпирического правила подразумевается разумный подход его исполнителя (в этом основные плюсы и минусы таких правил) Любое разумное правило можно довести до абсурда если его выполнять тупо и формально, не задумываясь о последствиях.


      1. bogolt
        22.06.2019 14:36

        хммм tryLock делает вот две вещи — проверят можно ли залочить мутекс и если можно лочит его.
        А если функция кроме своих действий пишет статистику это побочный эффект?

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


        1. vvbob
          22.06.2019 21:08

          «А если функция кроме своих действий пишет статистику это побочный эффект?»
          Да это побочный эффект, и да это плохо что на ней помимо основных обязанностей висит еще и «запись статистики». В таких случаях аспекты неплохо рулят — в функции нет ничего лишнего, но вся статистика по ее работе ведется… другой функцией, заточенной только под ведение статистики.

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


        1. yarick123
          22.06.2019 21:27
          +2

          Я воспринимаю сказанное автором следующим образом. Если именно в названии функции присутствует И, то тут, скорей всего, что-то не так. Функция с «хорошим» именем (без «и») функция при этом может делать несколько взаимосвязанных вещей, если это действие можно воспринимать… атомарно, что-ли. Понятно, что функция readFile должна и открыть файл, и прочитать его, и закрыть его. При этом у нас не возникает желания назвать такую функцию openFileAndReadItAndCloseIt.

          Точно так же с tryLock. К стати, я бы описал то, что она делает, несколько отлично от Вашего варианта. А именно: пробует захватить (залочить) мутекс. В случае успеха возвращает true, при неудаче возвращает false. Но это всё ерунда, в названии-то «and» не стоит ;)

          С записью статистики сложнее. Если статистика относится к действиям, выполняемым функцией, используйте «with» вместо «and». Или деепричастие, типа «tryLockSavingStatistics». Если же функция легко разбивается на две, неперекрывающиеся по функциональности, лучше разбить на две. Возможно на три, я об этом пишу в предпоследнем абзаце.

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


          О том-то и речь! Если не получается избежать «и» или синонимичного в данном контексте «потом», «затем»,…, значит, скорей всего тут дело нечисто, и лучше писать две функции.

          В целом, я вижу в этом не догму, а хороший способ проверки на вшивость своего кода. Опять же, разумные исключения/расширения в моём мире имеют право на жизнь. Скажем, в некоторых ситуациях может быть оправдано существование f1, f2 и f1ThenF2. Естественно, f1ThenF2 должна быть реализована посредством вызовов f1 и f2, а не, скажем, копированием и вставкой их тел, или, что ещё хуже, написанием кода «с нуля». Хотя и тут тоже могут быть исключения ;)

          В общем, по-моему, нужно понимать, с какими именно проблемами боролся автор, и делал соответствующие «записки на манжетах». Так же нужно понимать, что записка эта справедлива для определённого контекста. Да, в 80% или в 90% случаев контекст именно этот. Но вот оставшиеся 10%… Короче, проповедую подход без фанатизма :)


          1. yarick123
            22.06.2019 22:32

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

            То есть, и тут наличие «и» в имени (tryLockAndSaveStatistics), помогает увидеть ортогональную функциональность и задуматься о том, как бы её задействовать «прозрачно» по отношению к главной функциональности.


            1. bogolt
              23.06.2019 14:52

              хмм, понимаю о чем вы.
              Если я допустим собираю статистику по количеству операций над чем-то, то должен сделать специальную обертку которая при совершении операции будет и статистику собирать?
              Звучит неплохо, но как обычно детали. Статистика может например учитывать количество уникальных айпи адресов, и тут выходит что в методы по работе с бд придется передавать еще и метаданные запросы ( совершенно ненужные там если бы не статистика ). То есть сделать по-настоящему прозрачным скорее всего не выйдет.


        1. vvbob
          23.06.2019 09:42

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


    1. botyaslonim
      21.06.2019 11:20

      Флаги допустимы, були допустимы. JavaScript. Главное — написать документацию на функцию и перечислить входящие параметры. Нет ничего проще.
      То же касается и пресловутого «и». Я пользуюсь правилом, что в-основном надо избегать копипаста самой функциональности. Если 95% содержимого двух функций идентичны, и это не три строки, то можно использовать «и», почему нет?


      1. vassabi
        21.06.2019 11:26

        есть два варианта — или разбить на две или назвать без «и»:
        например функцию «поесть и попить» называем «пообедать».


        1. botyaslonim
          21.06.2019 11:34

          Я так понял, это его правило относится не к названию, а к функционалу: что делает функция.
          if (arguments.water) return попить
          if (arguments.meat) return поесть


          1. vvbob
            23.06.2019 09:37

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


  1. echmel
    21.06.2019 00:24
    +2

    Отладчики переоценены

    Я бы даже сказал, что порою недооценены. Вместо брейкпоинтов и дебага испльзуют print. Как же это «весело».
    Заведите список «того, что я не знаю»

    Уже сделал :) Хороший совет.


    1. iproger
      21.06.2019 02:41

      Всю жизнь в php пишу echo $x;exit; Давно уже знаю и пользуюсь xdebug, но для его запуска нужно выставить флаг, включить в браузере отправку (xdebug helper), в ide включить прослушку. Короче, легче написать то что выше написал.
      Бывают случаи когда приходится дебажить. Но это касается огромных структур данных, которые могут быть еще и закольцованы.


      1. pesh1983
        23.06.2019 23:31

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


    1. netch80
      22.06.2019 09:59

      > Я бы даже сказал, что порою недооценены. Вместо брейкпоинтов и дебага испльзуют print. Как же это «весело».

      В этом есть свой существенный смысл.
      Интерактивная отладка помогает получить текущее состояние — да, и жалкую часть истории в виде stacktrace. Самые продвинутые позволяют сделать лог срабатывания watchpoints с выводом состояния переменных при этом, но это фактически тот же лог (без перекомпиляции).
      А для очень многих ситуаций нужна целевая история, включая логи за много шагов назад. Вот поэтому и ставятся всякие print?ы.
      И это часто позволяет экономить часы и дни на ручном прохождении.


  1. webkumo
    21.06.2019 01:57

    System.out.println(ex);

    Ну и кто-же так делает-то? Всегда же каноничным было ex.printStackTrace();


    1. vvbob
      21.06.2019 09:06

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


      1. webkumo
        21.06.2019 10:19

        А это следствие дурацких холиворов checked exceptions vs unchecked exceptions. В какой-то момент времени было популярно ругаться на CE вплоть до молчаливого глотания оных. Вот тех, кто такую дурь придумал — надо уважить в первую очередь, а ваш говнокодер возможно и не виноват особо (ну тупо скопипастил с стековерфлоу… ну бывают такие говнокодеры, особенно в начале карьеры… а сейчас он может даже сожалеет об этом… ну или хотябы в UE запихивает эти самые CE, чтобы их выбросило где повыше).


        1. vvbob
          22.06.2019 11:13

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


  1. half-life
    21.06.2019 02:37

    Хорошие напоминания, в большинстве своём.


  1. CodeRush
    21.06.2019 03:24
    +1

    Многое очень спорно, но вот это реально покоробило:

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

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

    Отладка кода заведомо сложнее его написания, но почему-то автор не предлагает заменить свою IDE на ed, зато предлагает оказаться от отладчика, потому что он якобы «не оказывает помощи»…


    1. Zuy
      21.06.2019 07:08

      А что имеется ввиду под отладчиком, который можно подключить во время работы? Если у меня только одна ножка процессора доступна со светодиодиком это считается отладчиком или система с недостатком?


      1. CodeRush
        21.06.2019 16:38

        Ответ сильно зависит от того, что вы на вашем процессоре делаете.
        Если у вас там конечный автомат на десяток состояний, то вы его отлично отладите и так, а если у вас там РТОС на 50 процессов, активно работающая с внешним оборудованием, то система ваша явно с недостатком, т.к. даже на одну ногу можно завести отладочный интерфейс (debugWIRE у Atmel), а если отвоевать еще одну, то хватит на полноценный Test Access Port по cJTAG или SWD.


    1. ValdikSS
      21.06.2019 12:32
      +2

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


      1. CodeRush
        21.06.2019 17:44

        Если посмотреть на профиль автора на SO, то становится понятно, почему за 30 лет работы (неясно откуда взявшиеся, потому что он ВУЗ закончил в 2004 году) он так и не научился пользоваться отладчиками — просто не нужно было, все проблемы решались и без них.
        Это не означает, что проблем не было, это всего лишь означает, что эти "проблемы с медведями" решали совсем другие товарищи за совсем другие деньги.


        1. ValdikSS
          21.06.2019 18:27
          +2

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

          Но помните: не следует постоянно изменять данные; создавайте новые элементы с новыми значениями (считайте данные неизменяемыми)
          Вроде бы и правильно, но на каком-нибудь микроконтроллере 20 мГц и 64 кБ памяти больно не разгуляешься, а в каком-нибудь видео-кодировщике нужна максимально возможная производительность, и дополнительное копирование памяти тоже как-то не к месту.

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

          О чём вам нужно думать, так это о более качественном проекте для вашего кода, о том, как улучшить текущий код. Он нужен для того, чтобы его читали люди. ВСЕГДА. А оптимизациями занимаются компиляторы. Так что вместо использования более коротких слов найдите более толковый способ объяснить в коде, что вы хотите сделать.
          Тоже, вроде бы, правильно, но потом у вас в коде обнаруживается тайминг-атака, и приходится использовать битовые операции, чтобы за постоянное время выполнять какие-то манипуляции. А потом появляется Spectre и приходится переходить на вычисления без ветвлений.

          И ведь с анонсами технологий такая же ситуация. Встречайте — WebAssembly, теперь можно в браузере делать ВСЁ! Вот, смотрите, мы здесь запустили Doom, а вон там eBay сканер штрих-кодов из C скомпилировал! Читаешь и думаешь: «Охренеть, вот оно, будущее! Наконец-то, по-настоящему кросс-платформенные программы, прямо совсем-совсем без платформозависимого кода! И можно делать ВСЁ! Пойду делать торрент-клиент! Так, постойте, а как открыть TCP-сокет? Никак? Вообще никак? Мда.»

          … только отключите комментарии

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

          Отключите комментарии. Не позвольте другим вас остановить.
          …что и самого автора оставляет в неведении, и не дает читателям увидеть альтернативную точку зрения или просто что-то новое.


  1. Sergery8205
    21.06.2019 10:04

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


  1. DeveloperKZALA
    21.06.2019 10:40

    Автор постарался, спасибо! Моментами чувствовал дежавю :)


  1. OnYourLips
    21.06.2019 10:57

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


  1. vassabi
    21.06.2019 11:18
    +1

    Нет, я не думаю, что они могут «исправиться»

    Токсичных и микроагрессоров можно исправить, только если они — это ВЫ

    тут какое-то противоречие.

    PS: И да, я очень опасаюсь людей, которые на полном серъезе утверждают, что «они не могут исправиться». От таких убеждений всего полшага до «высших мер социальной защиты» (потому что «они же не исправятся, что с ними делать ?»)…


    1. COKPOWEHEU
      21.06.2019 14:47
      +1

      ИХ вы не исправите (пока они сами не захотят)
      Вы можете исправить СЕБЯ если осознали что ведете себя как один из них.


    1. SheolSatansfist
      21.06.2019 19:04

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

      Реально есть и другие варианты, но автор как минимум имеет право на свое мнение.


  1. e_v_genius
    21.06.2019 11:54

    Спасибо автору! Несомненно эта статья — отражение личного мнения автора, и с ней необязательно соглашаться. Но я согласен практически со всеми тезисами и доводами, так как мой личный опыт к 42 годам научил тому же. :-)
    Жаль лишь, что на заре профессиональной деятельности я не имел таких тезисов под рукой.


  1. corvair
    21.06.2019 11:54
    -1

    А на выходе всё тот же самый Therac-25.


  1. userNCh
    21.06.2019 19:04
    -1

    Потому что те, кто будут читать ваш код, увидят getUserMessage(userId, true) и будут недоумевать

    Можно делать так:
    ...
    let retrieveFullMessage = true
    getUserMessage(userId, retrieveFullMessage)
    


  1. Gabi4
    21.06.2019 19:04

    Хорошая статься, автору спасибо. Очень приятно и полезно в работе когда люди с огромным опытом делятся им. И не важно опыт положительный или отрицательный, главное чтобы он был обоснован пусть и субъективно. Всё же это позволяет взглянуть на процесс с иной стороны от теории описываемой в книгах.


  1. Shinbolat
    21.06.2019 19:04

    Да. Сэкономили нам 30 лет!


  1. third112
    22.06.2019 02:34
    -1

    Спасибо, интересная статья.

    А потом заполните кодом пустоты между комментариями.

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

    А здесь ИМХО нужен особый подход.
    getUserMessage(userId, true) очевидно плохо.
    Нужны константы с осмысленными именами:
    const
     retrieveFullMessageFl = true;
     retrieveShortMessageFl = false;
    

    И вызов записывать только с этими константами:
    getUserMessage(userId, retrieveFullMessageFl);
    getUserMessage(userId, retrieveShortMessageFl);
    


    1. Fedorkov
      22.06.2019 03:45
      +1

      И вызов записывать только с этими константами
      Можно сделать это принудительно, если вместо bool принимать enum.


  1. 411
    22.06.2019 07:42

    Очень часто основной приобретаемый навык за N лет работы — желание выдавать субъективное за объективное ввиду попытки оправдать важность этого опыта.


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


    1. yarick123
      22.06.2019 23:39

      Очень часто основной приобретаемый навык за N лет работы — желание выдавать субъективное за объективное ввиду попытки оправдать важность этого опыта.

      Я воспринимаю данную статью исключительно как субъективную. Автор решил много проблем, связанных с разработкой конкретного ПО. По результатам своего немалого опыта он сделал определённые выводы и поделился с нами. Правда, его субъективные выводы совпадают с моими субъективными выводами. С Вашими, похоже, не совпадают — на то они и субъективные. Но он молодец, что их записал и поделился.

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

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

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

      Альтернативы, как я понимаю, должен видеть сам читатель. Опять же, читателю стоит понимать, что абсолютной истины не существует, что всегда есть исключения,… Зачем об этом вообще упоминать в контексте «чему Я научился»?

      Вы видите, что должны быть альтернативы и исключения — Вы молодeц! Вы относитесь к целевой аудитории! Кстати, если Вы понимаете, что «нигде нет ни альтернатив, ни исключений, а во многих [тезисах] они должны были быть и в немалом количестве», (без сарказма) почему бы Вам о них не написать статью?


  1. vdem
    22.06.2019 10:16

    Уродское решение: создать новые функции, пометить текущую как нежелательную и добавить sleep в начало функции, чтобы заставлять обновляться тех, кто использует старую функцию.

    Вот это вообще за гранью :D Такого даже в индийском коде не встречал.
    В целом статья очень даже правильная, сам пришел практически к тому же (хотя иногда нарушаю эти правила).


  1. olezh
    22.06.2019 13:13
    +2

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


    Не смотря на здравые мысли о рабочем процессе, раздел «личное» очень удивляет.
    Словарь малопонятных терминов пополняется: к «токсичности» добавились «микроагрессии».
    И что это такое — объяснено очень плохо. Чужие неудачные шутки, или проявление неприязни к автору, или всё вместе?
    Я почему всё это пишу — меня потрясает эта позиция — убежать от конфликта, спрятаться, уволиться, так ничего и не выяснив. Такая за этим видится беспомощность уровня 5-летнего ребёнка.
    А вариантов — почему «микроагрессор» такой «микроагрессор» может быть масса, и правильный можно узнать только у самого человека.
    Все случаи не перебрать, отсечём самый неприятный вариант — если вы действительно не нравитесь кому-то, этот человек сам будет вас избегать. Это так работает. И в чём же проблема?


    1. vvbob
      22.06.2019 13:33

      Сильно от ситуации зависит, какую стратегию выбрать — «бей» или «убегай». В некоторых обстоятельствах попытка разобраться с конфликтом может оказаться слишком дорогой в плане времени, нервов или денег (или всего этого вместе), не всегда оно того стоит.