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

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

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

Отслеживание ошибок

Мы регистрируем все, что происходит с нашим программным обеспечением. Одним из наших лучших решений было настроить интеграцию между LogEntries.com и Slack; эта интеграция делает журналы гораздо более полезными и оперативными.

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

Чему я научился, наблюдая за подобными оповещениями?

  • Основные проблемы все равно будут.

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

Строки не являются объектами

Я действительно ненавижу человека, который решил создать в Java строковые объекты с методом «Equals». Я слышу их сейчас: «Все есть объект! Методы привязаны к объектам!»

Тем не менее практически половина ошибок, которые обнаруживаются в рабочем коде, выглядят так:

// This works great, right up until CountryCode becomes null
if (countryCode.Equals("US")) {

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

Все сравнения строк должны выполняться с использованием статики. Это единственный способ убедиться.

if (String.Equals(countryCode, "US")) {

Словари вызывают исключения

Еще одна распространенная проблема — проблема со словарем. В C# по умолчанию словарь выдает исключение, если вы дважды добавите в него объект.

Dictionary<string, object> dict = new Dictionary<string, object>();
// Since value.key is unique, this always works, right?
foreach (var value in list) {
    dict.Add(value.key, value);
}

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

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

Защитный подход будет таким:

foreach (var value in list.OrderBy(l => l.ModifiedDate)) {
    dict[value.key] = value;
}

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

Дизайн для обслуживания

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

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

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

  • Читабельность имеет решающее значение. Вы должны написать комментарии к коду; вы потратите гораздо больше времени на изучение старого кода в поисках ошибки, чем на написание новых функций.
  • Каждый файл в вашей кодовой базе должен иметь одну цель. Храните весь код, связанный с этой целью, в этом файле.
  • По возможности используйте статические функции, которые не изменяют глобальные переменные. Используйте как можно меньше входов и выходов.
  • Какой бы шаблон проектирования вы ни использовали, используйте его последовательно. Ни один шаблон проектирования не сделает ваше программное обеспечение совершенным по волшебству; постоянство означает, что новые члены команды могут изучить ваш стиль и вписаться в него.
  • Да, нужно будет оптимизировать. Нет, не следует оптимизировать до измерения. Лучший способ измерения — разделить код на красивые, легко читаемые фрагменты.

Хорошее программное обеспечение выживает

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

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

Это так приятно, когда кто-то новый присоединяется к команде и говорит: «Вау, этот код действительно классный! Я могу это понять, я могу прочитать, что было сделано, и я готов работать продуктивно!»