Программист разумный
[Об авторе: Руслан Дмитракович — разработчик ПО и предприниматель, в ИТ-индустрии с 1994 года. Пионер интернет-рекламы в Украине: основатель Украинской баннерной сети, рекламного агенства «Интернет-эксперт». Создатель проекта Code
Папа посылает сынка в магазин:
— Иди купи хлеб и молоко! Слышишь? Купи две вещи, две вещи! Хлеб и молоко! Две вещи! Понял? Понял?
Сынок покивал и пошёл. Приносит шайбу. Папаша орёт:
— Я тебе, что сказал? «Купи две вещи»! Две вещи! Где клюшка?!
Как ни странно, ситуации, похожие на анекдот выше, я встречал при разработке. Именно они подтолкнули меня написать о сложности. Программисты часто борются со сложностью созданых ими самими же продуктов. Изначально статья планировалась как чисто техническая, для программистов. Однако в ходе работы над ней, я понял: на то, что делают непосредственно разработчики, сильно влияет среда, в которой они находятся, корпоративная культура и менеджмент. И о том, что такое сложность, откуда она берется и как с ней бороться, стоит задуматься всем, а не только тем, кто непосредственно пишет код продукта.
Читая книги по разработке программного обеспечения, можно встретить следующие фразы:
«Программные проекты редко терпят крах по техническим причинам. Чаще всего провал объясняется неадекватной выработкой требований, неудачным планированием или неэффективным управлением. Если же провал обусловлен всё-таки преимущественно технической причиной, очень часто ею оказывается неконтролируемая сложность. Иначе говоря, приложение стало таким сложным, что разработчики перестали по-настоящему понимать, что же оно делает». Стив Макконнелл, «Совершенный код»
«Существенная черта промышленной программы — уровень сложности: один разработчик практически не в состоянии охватить все аспекты такой системы. Грубо говоря, сложность промышленных программ превышает возможности человеческого интеллекта». Гради Буч, «Объектно-ориентированный анализ и проектирование»
«Управление сложностью — квинтэссенция программирования». Брайан Керниган
Понятие «сложность» встречается часто, но, к сожалению, понимание этого термина дается на откуп читателю. Давайте разбираться!
«Фак ю, Спилберг, непонятно!»
Мой интерес к тому, как работает человеческий мозг, возник на обсуждении проекта. В ходе доклада человек, презентующий проект, показал вот такое:
Некоторое время я пытался понять картинку, слушал комментарии. Довольно быстро пришел к выводу, что человек с обычными мозгами (вроде моих) такую конструкцию не переварит. Мне она показалась слишком сложной (о чем я и сообщил докладчику). С утверждением, что диаграмма вполне понятна, я не согласился, но для того, чтобы не быть голословным пошел изучать теорию...
Говоря о сложности, мы всегда рассматриваем ее применительно к конкретному человеку, группе людей, ну или самому себе. Например, система уравнений для дошкольника сложная, практически неразрешимая задача. Для студента ее решение не составляет проблем. В этом случае знания и опыт являются ключевыми моментами. Студент делал это много раз и действует практически на автомате.
Точно также опытный разработчик ПО применяет типовое решение. Уже известны все за и против — берем и делаем. Поэтому важны теоретические знания — паттерны, методики, типовые алгоритмы. Их знание, конечно, не говорит о том, умеет ли разработчик распознать их при решении реальной задачи, но, как минимум, необходимо знать, что они есть. Однако не все можно свести к опыту и знаниям.
Человеческий мозг как вычислительная машина
Давайте рассмотрим когнитивные способности человека — его возможности воспринимать, запоминать и обрабатывать информацию. Вот несколько фактов:
- максимальный объем внимания, количество объектов, которые человек может воспринять одномоментно, колеблется от четырех до шести (оперативная память);
- мыслит нормальный человек однопоточно и переключение от одной деятельности к другой часто приводит к ошибкам, а также снижает темп работы (одноядерный процессор);
- количество логических операций в секунду сильно ограничено (тактовая частота) (для примера скажите, чему равно ( (true && !false) && (!true || false) ). Надеюсь, в пару секунд уложились. Нет? ;) );
- объем информации, воспринимаемый за единицу времени, также сильно ограничен (скорость коммуникационного интерфейса).
Есть любопытное исследование, касающееся последнего пункта. Разные языки обладают различной информационной насыщенностью слога в языке. Однако и количество слогов произносимых за единицу времени также разное. Например, испанский язык в полтора раза быстрее мандаринского наречия китайского языка. Однако китайский — в полтора раза более информационно насыщенный. Итого имеем примерно одинаковую скорость передачи информации для любого языка. Вот и выходит, что информационная пропускная способность — это в первую очередь характеристика человеческого мозга.
Сразу оговорюсь, что не рассматриваю сильные стороны — распознавание образов или ассоциативное мышление, в нашем случае они не важны.
Как видим, венец творения, с точки зрения выполнения алгоритма, выглядит не очень привлекательно. Человеческий мозг проигрывает программируемому калькулятору (лет 30 назад довольно популярная вещь), не говоря уже о чем-то более производительном.
Но самое главное, не всякий алгоритм человек выполнит с легкостью. Читая код программы, программист выполняет его в уме. И, например, параллельные вычисления, асинхронность, рекурсия («Я оглянулся посмотреть, не оглянулась ли она, чтоб посмотреть, не оглянулся ли я») обычно вызывают проблемы.
Поэтому, возвращаясь к понятию сложности, «сложным» можно называть тот объект или систему, чьи информационные параметры превосходят описанные выше возможности мозга. И, как следствие, нужно прилагать усилия для того, чтобы воспринять и обработать информацию.
Уровни абстракции или сильная сторона мозга
В отличие от компьютера, человеческий мозг может перескакивать на объекты разных уровней сложности, скрывая детали. Например, с точки зрения мозга, запомнить набор букв «П, Н, А, Т, Г» также сложно, как и набор слов «ПОЛ, НОГА, АНАНАС, ТИГР, ГАЗ».
Вернемся к истории c презентацией. Почему возникли разные мнения по поводу одного и того же изображения? Для того чтобы справляться со сложными (состоящими из многих частей) объектами, человек использует чанкинг: группировку информации таким образом, который позволяет лучше ее воспринимать и запоминать.
Диктуя или запоминая номер телефона, вы, скорее всего, будете использовать группу цифр, таким образом уменьшая количество объектов, которыми оперирует ваш мозг. Такие операции мы делаем подсознательно.
Практический совет: при написании кода старайтесь группировать строки небольшими блоками, которые можно легко понять и при желании выделить в отдельную функцию.
Готовя презентацию и перерабатывая изображение, докладчик «уложил» картинку в рамки своего восприятия, объединил в группу отдельные элементы, и картинка для него стала более «понятной» или «простой». Новый человек, получив на вход такое большое количество отдельных элементов и связей, не смог в короткий срок упорядочить увиденное. Как следствие, не воспринял картинку и определил ее как «сложную».
Как упоминалось выше, понятия «сложный» и «простой» очень сильно зависят от исходной информации, которой владеет человек. Презентатор имел больше знаний о предмете, понятиях и связях и не осознавал (или игнорировал) то, что у его слушателей этих знаний нет.
Одним из способов уменьшения сложности восприятия и улучшения понимания является язык. Язык имеет как коммуникативную, так и когнитивную функции. Познавая окружающий мир, человек создает слова, описывающие образы, предметы, понятия, таким образом формируя абстракции, которые потом используются в мышлении.
К сожалению, одни и те же понятия воспринимаются разными людьми по-своему. Отсюда и возникает путаница и недопонимание. Для того чтобы исказить информацию, достаточно просто не договориться о значении слов и пересказать ее несколько раз. Такая путаница вносит дополнительную сложность. Именно от этого эффекта пытались избавиться создатели DDD, предлагая использовать в общении между разработчиками и носителями знаний предметной области Единый язык.
Для программиста язык программирования является главным рабочим инструментом. Фактически создавая программу, программист описывает объекты и действия формальным языком. Однако тут существует дилемма. Код пишется для компьютера, но читают его люди. Даже если вы разрабатываете программу в одиночку, ваш двойник в будущем может не понять написанное, если какая-то информация уже забыта, а код написан сложно.
«Любой дурак может написать код, понятный компьютеру. Хороший программист пишет код, понятный человеку». Мартин Фаулер
Многие техники «чистого кода» основаны на том, чтобы обеспечить ясное понимание написанного, независимо от того, кто этот код читает. В основе легко сопровождаемого программного продукта лежит понимание ограниченности человеческих возможностей. Чем меньше необходимо мысленных преобразований, а также информации, которую нужно держать в памяти, тем проще понять код, схему или найти ошибку.
О сложности кода можно судить на основе метрик сложности. Хорошая идея включить автоматический анализ кода в процесс разработки. Но это тема для отдельной статьи.
Итак, создавая продукт, программный код или проектную документацию всегда нужно помнить о тех, кто потом будет с ней работать. Попробуйте поставить себя на место своего коллеги, проанализировать сделанное с точки зрения его знаний и опыта. Если вы понимаете, что знаете больше, делитесь этими знаниями. Так и с другой стороны, прежде чем ругать код, написанный другим разработчиком, попытайтесь разобраться, почему сделано так, а не иначе.
Отношения в команде и коммуникация
Исходя из написанного выше, очень важна коммуникация и отношения в команде. Соглашения и выполнение правил единых для всех унифицируют код проекта, делают его единообразным и более понятным. Коллективная разработка ПО — это не тот случай, когда нужно проявлять свою «уникальность».
Не раз замечал, что непонятный другим код часто пишут люди, которые не расположены к общению и не хотят считаться со своими коллегами. Как и в любом другом деле, взаимное уважение друг к другу, желание понять и договориться с другими членами команды очень сильно влияет на результат.
К сожалению нездоровый индивидуализм у представителей нашей профессии далеко не редкость. В моей практике не раз попадались герои-одиночки, очень грамотные специалисты, но совершенно не умеющие работать в коллективе. Был отлично рисующий дизайнер, который мог играть всю ночь, а потом просто не явиться на работу, хотя была договоренность обсуждать новое задание. Был программист, который за крайне короткие сроки мог решить сложную задачу, однако потом уходило много времени на то, чтобы разобраться, как работает его код.
Встречается и другая проблема. Некоторые персонажи, находящиеся на руководящих должностях, считают ниже своего достоинства опускаться до деталей реализации, разбираться в вопросе. В итоге важные моменты приходится решать самому исполнителю, внося дополнительную сложность в продукт.
Как ни странно, но на техническую реализацию влияет и культура компании: принятие решений, взаимодействие между разработчиками и менеджментом, обмен знаниями, процессы, атмосфера в коллективе, освоение новых подходов и технологий и т. д. Все это находит отражение в коде.
Культура компании влияет на коммуникацию и знания коллектива, а те, в свою очередь, влияют на реализацию проекта.
И, конечно, общение на одном языке, как в проекте, так и компании в целом. Однозначное понимание того, что сказал ваш коллега, может сильно облегчить жизнь и ему, и вам.
Ревью, работа в паре и «шкаф». Или одна голова хорошо, а две лучше
Человеку свойственно ошибаться. Ошибки при создании програмного обеспечения — нормальное явление. Ошибки бывают самыми разными, и мы не будем углубляться в подробности. Но все они связаны с тем, что человеческий мозг работает не так идеально, как хотелось бы. В силу ограничений мозга, описанных выше, разработчик что-то упускает из виду и делает ошибку. И вот тут применима пословица «Одна голова хорошо, а две лучше». Вовлекая в процесс коллегу, мы тем самым включаем механизм контроля и обратной связи. Таким образом мы увеличиваем «вычислительные ресурсы», направленные на решение задачи. Конечно, мы начинаем терять часть времени на коммуникацию, но качество работы растет.
Питер Друкер, один из самых влиятельных теоретиков менеджмента, отмечает, что в области обработки знаний, команда, а не один человек, становится рабочей единицей. Это можно объяснить как раз тем, что один человек не в состоянии перерабатывать те массивы информации, с которыми приходится сталкиваться при решении современных информационных задач.
Есть несколько вариантов взаимодействия, когда вы можете управлять затратами на коммуникацию, но в тоже время использовать ресурсы коллеги:
- «Шкаф» — самый простой, быстрый, но в тоже время эффективный способ. Просто расскажите кому-то, что вы собираетесь делать. Очень вероятно, что вы сами заметите ошибку. Дело в том, что, проговаривая решение, вы включаете в работу еще одну часть своего мозга и таким образом полнее используете его возможности.
- Коллективное обсуждение решения, мозговой штурм.
- Ревью кода коллегами. По моим наблюдениям, качество анализа кода коллегами сильно зависит от объема просматриваемого кода. Поэтому в случае большого количества кода, который требует анализа, я предпочитаю просматривать код вместе и задавать вопросы.
- Парная разработка. Данный метод хорошо работает для задач средней сложности, не требующих высокой концентрации. Таким образом у вас получается процесс 3 в 1: создание продукта, обсуждение и анализ выполненной работы. Однако, по моим наблюдениям, если решение не очевидно, то задача может «забуксовать» и более эффективно использовать в наборе техники, описанные выше.
Выводы
«Сложность» — одно из самых важных понятий, которым должен владеть разработчик ПО и всегда помнить о нем в своей повседневной деятельности.
Понимание, что такое «сложность» проистекает из осознания ограниченности умственных способностей человека. В большинстве случаев работает принцип: больше, значит сложнее. Больше строк кода, больше файлов, больше связей, больше состояний — все это означает усложнение программного проекта.
Вот несколько способов уменьшить сложность при разработке:
- налаживайте коммуникации в команде, совершенствуйте язык общения, стандарты и соглашения. Учитесь слушать и понимать друг друга;
- обращайте внимание на количественные параметры создаваемых объектов: количество файлов в каталоге, методов у класса, состояний объекта или переменной, связей между компонентами и т. д. При достижении установленного предела перерабатывайте проект;
- используйте фреймворки, библиотеки и инструменты, позволяющие скрыть сложность в уже существующих компонентах;
- используйте языки и нотации, наиболее подходящие для решения вашей задачи. Например, SQL может быть самым лаконичным и понятным средством для построения отчета, а для описания бизнес-процесса нотация BPMN.
Напоследок повторю избитую цитату:
«Управление сложностью — самый важный технический аспект разработки ПО. По-моему, управление сложностью настолько важно, что оно должно быть Главным Техническим Императивом Разработки ПО». Стив Макконнелл, «Совершенный код»
Не забывайте об этом!
55 коментарів
Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.