Прежде чем беспокоиться о сложных вещах, убедитесь, что простые части работают.
Высококлассное программирование — это не только обсуждение алгоритмов и выбор передовых решений для хранения без 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 сначала достигнет более старого значения, присвоит его словарю, а затем более новое значение перезапишет его без сбоя.
Дизайн для обслуживания
Очень важно помнить, что ваше программное обеспечение — это живая, дышащая система, в которую вносят свой вклад многие члены команды. Программное обеспечение, разработанное так, чтобы его было легко поддерживать, в конечном счете победит умный и малопонятный код, написанный гением.
Гении увольняются, надоедают, переходят к другим вещам. Когда они уйдут, кто-нибудь еще сможет забрать их? Кто-нибудь захочет?
Планирование вашего программного обеспечения похоже на создание базы в стратегической игре: вы можете броситься и просто соединить все части где угодно, но результат будет трудно поддерживать.
- Читабельность имеет решающее значение. Вы должны написать комментарии к коду; вы потратите гораздо больше времени на изучение старого кода в поисках ошибки, чем на написание новых функций.
- Каждый файл в вашей кодовой базе должен иметь одну цель. Храните весь код, связанный с этой целью, в этом файле.
- По возможности используйте статические функции, которые не изменяют глобальные переменные. Используйте как можно меньше входов и выходов.
- Какой бы шаблон проектирования вы ни использовали, используйте его последовательно. Ни один шаблон проектирования не сделает ваше программное обеспечение совершенным по волшебству; постоянство означает, что новые члены команды могут изучить ваш стиль и вписаться в него.
- Да, нужно будет оптимизировать. Нет, не следует оптимизировать до измерения. Лучший способ измерения — разделить код на красивые, легко читаемые фрагменты.
Хорошее программное обеспечение выживает
Создание продукта — это и спринт, и марафон. Вы должны выйти на рынок с чем-то хорошим; но тогда вы также должны выжить. Эти две разные цели требуют разных навыков и стратегий.
Так много программистов любят острые ощущения от запуска чего-то замечательного и наблюдения за тем, как мир использует это; но в то же время есть и другое волнение: радость наблюдать, как отличный продукт медленно растет, адаптируется и добавляет новых членов команды, не ломаясь.
Это так приятно, когда кто-то новый присоединяется к команде и говорит: «Вау, этот код действительно классный! Я могу это понять, я могу прочитать, что было сделано, и я готов работать продуктивно!»