Disclaimer
Коллеги, вашему вниманию предлагается почти финальный вариант моей книжки. Была и остается идея издать это в бумажном варианте, но идея довольно зыбкая. К сожалению, имеются некоторые проблемы со здоровьем. Но очень хочется, чтобы труд не пропал, поэтому книжка отдается в открытый доступ. Можно публиковать где угодно, цитировать и так далее. Единственное условие — ничего в тексте не менять и указывать авторство. Автор текста — Никита Викторович Зайцев (также известный как WildHare).
Книжка повествует об эффективной разработке программного обеспечения. Можно сказать, что это дистиллят моей личной практики, наработанного опыта, знаний и умений.
Предыстория появления книжки в формате интервью порталу Инфостарт:
//infostart.ru/journal/news/mir-1s/nikita-zaytsev-ya-universalnyy-soldat-v-mire-1s_1250753/
Это уже не полуфабрикат, а почти готовый продукт, правда без нескольких не особо важных деталей. Если работу над книжкой получится продолжить, то эти недостающие детали будут добавляться именно сюда, в эти файлы.
Приятного чтения ;-)
Краткий курс политэкономии
Два пути через торфяное болото разработки
Как и почти в любом деле, в разработке программного обеспечения (и не только на платформе “1С:Предприятие”, это универсальный принцип) можно выделить два принципиально разных подхода.
Быстро и криво
Простой подход — сделать быстро, затратив минимум ресурсов. Пускай будет слегка криво, пускай не будут учтены нюансы эксплуатации, пускай кое-где вылезают ошибки. Зато заработает (как мы всегда надеемся) прямо сразу. Ну а потом исправим ошибки, напишем документацию, отработаем замечания заказчика, и сделаем еще десяток добрых и полезных дел.
У такого подхода есть одно серьезное преимущество. Если расположение звезд окажется удачным, а разработчик более-менее опытным — действительно, что-то заработает прямо сразу. И какое-то время это “что-то” будет функционировать.
Но есть и три не менее серьезных недостатка. Во-первых, результат разработки в стиле “быстро и криво” далеко не всегда начинает работать прямо сразу. Практика показывает, что запуск частенько проходит в строгом соответствии со старой шуткой о промышленном шпионаже, где “после сборки тщательно обработать напильником”.
Во-вторых, результат разработки с вероятностью практически 100% попадает хотя бы в одну из типичных ловушек:
- Неустойчивость к входным данным (“Очень странно, у меня же все загружалось”). При написании кода использовались самые примитивные примеры, а в реальных данных заказчика оказалась закопана добрая дюжина грабель с прочными дубовыми черенками.
- Несоответствие техническому заданию и ожиданиям заказчика в целом. (“Но мы думали, что здесь нужно просто создать и записать документы, а чтобы при повторной загрузке изменять ранее созданные речи вроде бы не было”). Прямое следствие методики “код пишется параллельно чтению технического задания”. Задание читается по диагонали, писать код значительно интереснее.
- Неполнота реализации требуемых функций. (“Протоколирование мы пока еще не сделали, и в отчете пока только две колонки без детализации. Это мы потом доделаем, но данные загружать можно уже сейчас”). Заказчику предлагается что-то вроде легкового автомобиля без стекол и кресел, но можно же пока табуретку поставить? Используя инженерную смекалку, всегда можно найти временное решение. Беда (для заказчика) в том, что временные решения с течением времени получают статус постоянных, раз уж выдержали проверку временем.
- Наличие элементарных ошибок. Под “элементарными” здесь понимаются такие ошибки, которые возникают в основном потоке событий приложения, причем с валидными входными данными. (“Здесь нужно пока не обращать внимания, просто нажмите Отмена, а дальше сначала нажмите Обновить, потом снимите и сразу поставьте обратно эту галочку, а потом уже Сформировать” — представитель заказчика лихорадочно записывает на бумажку). Методика “Мы просто пишем код”, к сожалению, не предполагает затрат труда и времени на альфа-тестирование хотя бы основного потока событий, не говоря об альтернативных потоках.
- Низкое качество кода в плане сопровождения и развития функциональности. (“Нет, эту функцию добавить не получится, тут нужно будет почти все полностью переписать. Почему? Какие сроки были поставлены, вы помните? Поэтому и переписать” — через месяц после запуска. “Кто же это вам такую красоту написал? Руки бы оторвать, тут нужно все переделать с нуля” — через шесть месяцев, от представителя другой команды специалистов).
Почему так?
— Ибо дело, свершенное в спешке, никогда не бывает свершено наилучшим образом.
Памятка руководителю. Опознать методику “Быстро и криво” можно по внешним родовым признакам, даже не заглядывая в код. Вот некоторые из них:
- Соотношение трудозатрат на разработку и отладку не менее, чем 50/50.
- Отсутствие внятных пользовательских инструкций.
- Большое (больше двух) количество итераций “сдали результат — попробовали эксплуатировать — что-то не работает — вернули на доработку”.
- Наличие ошибок, которые обнаруживаются вторым-третьим кликом.
- “Эта ошибка уже была в одной из предыдущих версий, но ее же исправили?”
Нельзя сказать, что подход “Быстро и криво” является абсолютным злом. Существует несколько классов задач, где такой подход действительно позволяет существенно сэкономить трудовые и временные ресурсы.
- Быстрое прототипирование. Проверить гипотезу, понять принцип действия какого-то механизма платформы, попробовать сопряжение с каким-то сторонним API, и так далее. Но здесь нужно четко понимать, что “быстрый прототип” делается на выброс, это даже не временное решение, а просто пробник.
- Ликвидация аварий. При тушении пожара хороши любые средства, и когда система собирается падать (или уже падает), вопросов “насколько грамотно, изящно и эффективно написан подпирающий код” не возникает в принципе. Только нужно не забыть потом заменить вбитые костыли добротной инженерной конструкцией (см. “временные решения”).
- Одноразовые инструменты “для себя”. Когда требуется написать, например, какой-то крохотный корректировщик данных вида “использовал и выбросил”, забивать себе голову альтернативными потоками событий, снижением издержек на сопровождение и другими высокими соображениями абсолютно незачем.
Иными словами, молоток нужен, чтобы быстро забивать гвозди, но далеко не каждая задача представляет собой гвоздь.
Не спеша, эффективно и правильно
Подход посложнее — не спешить с написанием кода, не пытаться выкроить лишний грошик на ресурсах. Разработка даже самого простого механизма, самой элементарной, казалось бы, функции, выстраивается в несколько стадий:
- Анализ. Изучение задачи, изучение текущего положения, выявление противоречий, уточнение неочевидных мест, допущений и ограничений.
- Проектирование. Разработка “на бумаге”. Принятие основных проектных решений (при необходимости с проверкой на быстром прототипе).
- Кодирование. Собственно написание и отладка кода. Честно говоря, это не самое захватывающее занятие — если все продумано и правильно спроектировано, код является очевидным, и очень жаль, что сам себя он писать пока еще не способен.
- Проверка. Прежде, чем передавать какую-то разработку хотя бы на тестирование, разработчик обязан самостоятельно проверить, по крайней мере, основной поток событий и поток наиболее очевидных ошибок.
- Документирование. Написание инструкций по развертыванию, эксплуатации, разрешению известных проблем. Фиксация “на бумаге” наиболее важных и/или сложных проектных решений.
Кажется слегка громоздким, верно? Но все дело в масштабировании. Если мы пишем простенькую обработку, стадии анализа и проектирования можно пройти за десять минут, не написав ни слова, а инструкция будет представлять собой короткую надпись на форме. Важно, чтобы в любом случае все пять стадий имели место, и ровно в указанном порядке.
У этого метода, разумеется, тоже имеются недостатки.
- От разработчика требуется не только квалификация в собственно написании кода, но еще и способность к абстрактному мышлению.
- Что еще хуже, от разработчика требуются также зачатки бизнес-анализа, то есть умение мысленно поставить себя на позицию пользователя. Никакой “работы по четкому ТЗ” здесь не будет, любое ТЗ придется потрошить в поисках противоречий и недоговорок.
- Прямо завтра ничего не заработает. Прежде, чем поехать, какое-то время будем запрягать.
- Эффективная и вдумчивая разработка кажется значительно дороже быстрой и бездумной. Причем кажется не какому-то воображаемому критику, а собственному руководству и представителям заказчика.
Преимущества методики “Не спеша, эффективно и правильно” зеркально повторяют недостатки методики “Быстро и криво”: система устойчива к любым входным данным, соответствует ожиданиям, содержит минимальное количество ошибок (причем некритичных), вполне пригодна для сопровождения, а дальнейшее развитие не потребует переписывать все заново.
Смертельная схватка цены и качества
Казалось бы, вопрос только в цене, которую мы (и наш заказчик) готовы заплатить за качество. Либо “быстро, криво, дешево”, либо “медленно, качественно, дорого” — как нарисовано на всем известной картинке-мотиваторе “Памятка заказчику”.
Так? Не совсем, есть нюансы.
Закон сохранения стоимости
Дело в том, что любая задача разработки по своей сути является чьей-то проблемой. В создание этой проблемы был вложен определенный объем труда. Соответственно, для полноценного решения задачи также потребуется вполне определенный объем труда, и ни одним нормо-часом меньше.
Здесь работает брат-близнец фундаментального закона, названного именами Ломоносова и Лавуазье (хотя кто только этот закон не сформулировал, в европейской истории начиная с Эмпедокла, а в мировой — наверняка еще на стенах пещер царапали). Наиболее же остроумную трактовку фундаментального закона, регулирующего соотношение труда и стоимости, предложил Скотт Адамс в своей замечательной книге “Принцип Дилберта”.
И если разработка ведется поспешно, с низким качеством и установкой “сэкономить на кодировании” — да, это будет дешево, заказчик платит только часть реальной стоимости. Но и взамен получает только частичное решение своей проблемы — как в той старой сказке, где посетитель трактира вдыхал аромат приготовленных блюд, а трактирщик в уплату слушал звон зажатых в руке посетителя монет.
Частичность результата может иметь самые разные формы, например:
- Автоматизированы не все действия, которые могли быть автоматизированы. Как следствие — пользователи затрачивают свое рабочее время на лишние ручные операции.
- Не проверяются входные данные, нет защиты от неправильных действий пользователей. Следствие — множественные ошибки ввода.
- Отсутствуют средства протоколирования. Следствие — невозможно разобраться в причинах некорректного поведения системы (это пользователь ввел что-то не так? или система посчитала неправильно? звезды не так стояли?), для групповых операций невозможно “откатить обратно” или “запустить заново с места сбоя”.
- Код написан и организован таким образом, что добавление любой новой функции и/или модернизация любой существующей требуют затрат, сопоставимых с исходной разработкой.
- Большое количество ошибок в коде приводит к периодическим сбоям и простоям (а это тоже затраты заказчика, пускай и косвенные).
- Ну — и так далее.
Общее во всех этих пунктах — методика “быстро и криво” на стадии разработки закономерно приводит к паттерну “криво, медленно и печально” на стадии эксплуатации.
Можно сравнить с экономией на туалетной бумаге в домохозяйстве, если, конечно, такое сравнение будет уместным. “Экономной” хозяйке кажется, что покупать качественную, четырехслойную бумагу — дорого. Но никто не принимает во внимание, что, если покупать самую дешевую, которая расползается прямо в руках, придется использовать ее на американский манер, сворачивая в шесть рядов. И если посчитать хотя бы квартальный домашний бюджет, по деньгам выйдет примерно столько же, а вот по удобству — да сами попробуйте.
Парадокс убыточного удешевления
Но самое интересное заключается в том, что закон сохранения стоимости имеет только нижнюю планку и в окончательной редакции “для реальной жизни” выглядит следующим образом:
Разработка по методикам семейства “быстро и криво” не может обойтись дешевле, чем разработка по методикам семейства “не спеша, эффективно и правильно”. Но при должном радиусе кривизны может обойтись и значительно дороже.
Это важный момент, и мы разберем его подробно, на конкретном примере из реальной практики автора. Без имен и названий, разумеется (хотя действующие лица, если текст попадется им в руки, без сомнения, себя узнают). Масштаб слегка искажен, и для наглядности, но в первую очередь потому, что NDA нужно уважать.
Место действия — очень масштабный и амбициозный проект по разработке и запуску большой и по-хорошему страшной информационной системы. Один из этапов проекта — перенос (миграция) почти тысячи локальных систем со всеми данными “с земли” в единую систему. “Наземные” системы относятся к нескольким разным типам, из которых только одна реализована на платформе “1С”. Предельно сжатые сроки, чудовищные штрафные санкции за срыв графика, кривые локальные базы, активный саботаж на местах — все, как мы любим.
Инструментарий миграции заказали стороннему подрядчику, своих ресурсов на разработку не было. Но совершили серьезную ошибку — дали подрядчику полную свободу действий. Никто не курировал разработку, никто не проводил аудит промежуточных результатов. Ну а подрядчик подошел к делу творчески, в полном соответствии с поговоркой про сберегающую рубль копеечку.
Концептуальная часть инженерного решения была вполне грамотной. Если мы сводим данные из пяти разнородных систем в одну, разумным представляется разработать некий промежуточный формат, перегонять локальные данные в унифицированные файлы, а затем уже загружать в единую систему. Прекрасное решение, без шуток.
Но вот техническое воплощение этой концепции в личном рейтинге автора по сию пору занимает безусловное первое место в номинации “Быстро и криво”.
Во-первых, в качестве формата для промежуточных данных был выбран файл MS Excel, причем записанный строго определенной версией. Формат, который не обеспечивает даже элементарное “прочитано будет ровно то же значение, которое было записано”. И попробуйте объяснить ответственным за инфраструктуру, что на серверах нужно установить MS Office такой-то, и чтобы можно было вызывать Excel через COM-соединение. Особенно когда чуть ранее была поставлена задача перевести хотя бы часть серверного парка на Linux.
Почему же был выбран самый неудобный формат? Почему не JSON, не XML, даже не xBase? Подрядчик, разумеется, настоящую причину не озвучил. А заключалась она в том, что у “программиста”, которому была поручена реализация, имелись некие готовые механизмы по работе с файлами Excel. И чтобы не писать код заново (а еще, не дай бог, не тратить время на изучение приемов работы с JSON/XML), проще эксгумировать старый код и как-нибудь натянуть его на задачу. Экономия трудозатрат? Ударная скорость разработки? Вне всякого сомнения™.
Во-вторых, было принято техническое решение класса “epic” — не изобретать какие-то свои механизмы загрузки данных, а слегка допилить уже встроенную в типовое решение механику перехода с предыдущей редакции (здесь следует передать горячий привет “правилам конвертации”, и мы не упустим такого случая — “Привет, правила! Идущий к ручь
Вступайте в нашу телеграмм-группу Инфостарт