Это циничная, клиническая коллекция того, чему я научился за 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, только без питоновской части.
Заведите список «того, что я не знаю»
У Ричарда Фейнмана, известного физика, был блокнот, озаглавленный «То, чего я не знаю».
Когда вам попадётся что-то интересное и вы хотите больше об этом узнать, создайте файл, заведите блокнот или что-нибудь ещё с подобным заголовком. А затем делайте заметки о том, что вы нашли или выяснили.