С конкретными примерами того, почему они полезны

Представьте, что у вас есть смартфон без приложений. Звучит не очень полезно, правда? Мозг без каких-либо ментальных моделей - это, по сути, смартфон без каких-либо приложений. Установка правильных приложений может серьезно улучшить качество вашей жизни. Изучение правильных ментальных моделей может сделать то же самое для вашего мозга.

Вы программист, и я собираюсь предложить вам на рассмотрение три ментальные модели. Вы можете сомневаться в моей правдивости, и вы правы, если отнесетесь к этому скептически. В конце концов, я не Мартин Фаулер.

Однако за свою карьеру программиста я поработал над изрядным количеством интересных задач. За прошедшие годы у меня было:

  • Устанавливаю новый стандарт модульного тестирования в моей компании, создавая целую фиктивную библиотеку.
  • Выполнена оптимизация критически важного уровня кеширования для сезона высокой загруженности.
  • Предоставляет основные функции для флагманского продукта, используемого десятками миллионов пользователей.
  • Развернул сервис машинного обучения в реальном времени в производственной среде.
  • Масштабирование ETL для создания карты сайта до сотен миллионов URL-адресов.
  • Занял первое место в группе хакатонов.

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

Их три, начиная с самого простого.

1. Негативное пространство

Вместо того, чтобы всегда сосредотачиваться на том, что есть, зачастую более продуктивно сосредоточиться на том, чем не является.

Начнем с простого примера. Если вы когда-либо проходили тест с несколькими вариантами ответов, я уверен, что вы ответили хотя бы на один вопрос, вычеркнув все неправильные ответы. Это известно как процесс исключения.

Теперь рассмотрим бинарный поиск. Он находит индекс целевого значения в отсортированном массиве. Его главный аргумент в том, что он невероятно быстр. Двоичный поиск достигает O(log(n)) скорости за счет сокращения пространства поиска вдвое с каждой итерацией. Другими словами, он агрессивно вычеркивает неправильные ответы. Когда это будет сделано, просто появится правильный ответ.

Двоичный поиск - это пример использования отрицательного пробела для решения проблемы. Он рисует контуры ответа, который нас волнует, заполняя отрицательное пространство.

Рассмотрим еще пару примеров.

Более простое сопоставление с образцом

Одно из моих любимых применений отрицательного пространства - это регулярные выражения. Часто сложное регулярное выражение можно превратить в простое, отрицая критерии соответствия. Допустим, мы хотим сопоставить части строки, заключенные в фигурные скобки:

The {quick brown fox} jumps over the {lazy dog}.

До того, как я познакомился с этой ментальной моделью, моя интуиция должна была сосредоточиться на каждом персонаже, который может появиться между фигурными скобками. Это означает буквенно-цифровые символы, пробелы, новые строки, кавычки, знаки препинания и т. Д. Моим решением было бы что-то вроде \{[\!\-\w\s\'\"\,\.\/\?]+\}.

Этот подход не только излишне сложен, но также, вероятно, даже не соответствует всем интересующим персонажам. Поэтому вместо того, чтобы пытаться сопоставить каждый символ, который может появиться внутри фигурных скобок, мы можем отрицать критерии и пытаться сопоставить все, что не закрывающей фигурной скобки. Результат \{[^\}]+\}.

{quick brown fox}, {lazy dog}

Отрицательное решение является более полным и более легким для понимания.

Написание чистого кода

Фундаментальный закон программирования, как заявил Джоэл Спольски, заключается в том, что читать код сложнее, чем писать. И один из шаблонов, который особенно затрудняет поиск фрагмента кода, - это вложенный оператор if.

Вот пример:

Основная логика в приведенном выше коде работает со списком целых чисел, которые в сумме дают положительную сумму. Однако, чтобы добраться до основной логики, мы должны пройти несколько уровней if операторов. Это затрудняет чтение кода. Читатель должен отслеживать набор ограничений, которые применяются к каждому пути кода, что является огромной когнитивной нагрузкой.

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

Вычеркивание исключительных случаев одно за другим привело к сглаживанию вложенного оператора if. Теперь очевидна основная логика, и легче идентифицировать крайние случаи. И снова ментальная модель негативного пространства дала нам гораздо более понятное решение.

Если у вас возникли проблемы с решением конкретной проблемы, попробуйте использовать отрицательное пространство, чтобы найти элегантное решение.

2. Принцип Парето

Также известно как правило 80/20. Многие люди уже знают эту ментальную модель, но она настолько полезна, что я все равно решил включить ее сюда. Принцип гласит, что примерно 80% эффекта происходит от 20% причин. Это может звучать как миф, но это не так.

Например:

  • Небольшая клиентская база приносит большую часть дохода (особенно это касается мобильных игр с так называемыми «китовыми» пользователями).
  • Несколько модульных тестов ответственны за большую часть замедления.
  • Незначительная часть кодовой базы ответственна за большинство ошибок.

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

Обретение высокого кредитного плеча

Одним из интересных свойств принципа Парето является масштабная инвариантность, что просто означает, что 20% из 20% (4%) отвечают за 80% из 80% (64%). И, в более широком смысле, примерно 1% причин ответственны за 50% следствия. Вы знаете, что это правда, если вам когда-либо приходилось сдавать экзамен накануне вечером, и все же каким-то образом удавалось получить проходную оценку.

Многие вещи в жизни следуют этой общей схеме.

Вы можете использовать эти знания, чтобы найти два вызова настройки, которые вызывают 50% замедления в вашем наборе тестов (что-то, что я действительно видел на практике), или установить приоритеты и реализовать функцию, которая принесет наибольшую пользу пользователю. (вместо того, чтобы отвлекаться на другие функции, над которыми вы хотите работать).

Но что меня больше всего волнует в принципе Парето, так это его значение для изучения нового. Например, вы можете пройти вводный курс по таким технологиям, как Docker (контейнеризация), Kubernetes (развертывание службы) и Terraform (инфраструктура как код), и получить огромные преимущества, такие как развертывание масштабируемой службы, в которой управляются желаемые состояния и ресурсы. декларативным кодом - с базовыми знаниями.

Очевидно, это помогает узнать больше, но многие идеи дают наибольшую отдачу от инвестиций в обучение, когда вы только начинаете. Ключ в том, чтобы сосредоточиться на поиске тех частей знания, которые обладают наибольшим потенциалом. Да, и будьте осторожны, чтобы не стать жертвой эффекта Даннинга-Крюгера.

Высокая производительность

Возможно, что более спорно, примерно 20% инженеров выполняют 80% работы в данной технологической компании (где 1% - инженеры-«герои»). Для этого есть много возможных причин:

  • Новые инженеры незнакомы с системой, поэтому не могут внести существенных изменений. С другой стороны, инженеры, проработавшие в компании долгое время, имеют более глубокое понимание системы и могут использовать свои знания.
  • Эффект снежного кома, когда инженеры, успешно завершившие большие важные проекты, завоевывают доверие компании и продолжают выполнять больше крупных и важных проектов, оставляя меньше возможностей для инженеров без столь впечатляющего послужного списка.
  • Неравномерное распределение инженерных талантов.

Для инженерных менеджеров это означает, что они должны внимательно относиться к наиболее эффективным инженерам и прилагать усилия, чтобы удержать их в компании. Однако они также должны проявлять искренний интерес к развитию других инженеров, чтобы они также могли стать высокопроизводительными специалистами.

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

Пища для размышлений относительно производительности - это то, что Малкольм Гладуэлл сказал в своей книге Давид и Голиаф: Вы можете быть либо большой рыбой в маленьком аквариуме, либо маленькой рыбкой в ​​большом аквариуме.

3. Стационарность во времени

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

Ментальная модель стационарность времени в основном задает вопрос: насколько стационарно (неизменным) что-то по отношению ко времени?

Интересно подумать о том, что делает что-то постоянным во времени. Например, рассказывание историй - это вечный навык. Это умение, основанное на стремлении людей понимать мир через истории. А поскольку скорость изменения человеческой природы ограничена эволюцией (медленный процесс), рассказывание историй останется ценным навыком в обозримом будущем.

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

Основополагающий кодекс

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

  • Люди хотят работать над новыми вещами.
  • Устаревшие системы сложно изменить.

И снова интересно подумать, почему устаревшую систему сложно изменить:

  • Код трудно читать, потому что соглашения могли быть другими, когда он был написан.
  • Единственные люди, которые были знакомы с кодом, могли покинуть компанию.
  • Возможно, самое главное, что многое может сломаться, если мы изменим код.

В своем разговоре о принципах проектирования SOLID Сэнди Метц объясняет разницу между кодом, который изменяется медленно, и кодом, который изменяется быстро. В общем, изменчивый, быстро меняющийся код (тот, который изменяется в соответствии с бизнес-требованиями) должен зависеть от стабильного, медленно меняющегося кода (общие абстракции, такие как итераторы).

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

Так что все это значит?

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

Помните принцип Парето: правильная основа принесет непропорциональную выгоду.

«Правильная [основная] абстракция значительно улучшит ваш код». - Санди Мец

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

Хуже всего в том, чтобы исправить это позже, это то, что это всегда занимает больше времени, чем ожидалось.

Вечное знание

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

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

Общей чертой этих быстро меняющихся процессов является то, что они горячие. Эта область интересует многих людей, поэтому она быстро развивается. И у нас есть веские причины для того, чтобы следовать горячим темам. В конце концов, мы не хотим упускать важные новости.

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

Джеффри Хинтон, один из крестных отцов глубоких нейронных сетей, не произвел революцию в области машинного обучения, проследив за тем, что делали все его современники. Он смотрел в прошлое в поисках вневременных хороших идей. Хинтон взял перцептрон - технику машинного обучения, которую все считали устаревшей - и превратил ее в революционную идею, известную сегодня как глубокое обучение.

Итак, каковы некоторые стратегии выявления вневременных знаний? Что ж, есть по крайней мере три способа, которыми что-то может быть стационарным во времени:

  • Это зависит от медленного естественного процесса, который мы не можем контролировать, например, от эволюции человека. Подумайте: рассказывание историй, лидерство и обучение тому, как учиться.
  • Он служит основой для многих других вещей. Изменения будут болезненными, так как они могут сломать множество вещей, построенных на фундаменте (подобно землетрясению). Подумайте: операционные системы, компьютерные сети и криптография.
  • Это происходит из физических или абстрактных истин. Подумайте: теория графов, линейная алгебра и большинство других разделов чистой математики.

В своей жизни я снова и снова обнаруживал, что извлекаю пользу из вневременных знаний. Курсы по операционным системам и параллелизму помогли мне отладить некоторые из самых сложных ошибок в моей карьере программиста. Курс по криптографии позволил мне выявлять и исправлять уязвимости в кодовой базе моей компании. Изучение коммуникативных навыков позволило мне проводить увлекательные презентации для моих коллег.

Обязательно идите и изучайте горячие новые технологии, которые вас волнуют. Но также не забудьте разнообразить свое портфолио, изучив неподвластные времени навыки.

Заключительные мысли

Обобщить:

  1. Когда проблема кажется сложной, попробуйте сосредоточиться на отрицательном пространстве.
  2. Найдите высокое плечо, помня принцип Парето.
  3. Инвестируйте инженерные усилия и диверсифицируйте свои навыки на основе стационарности во времени.

Перед тем, как опубликовать эту статью, я подумал о том, чтобы назвать ее «Лучшие 3 модели мышления для программистов». Но это было бы ложью (и приманкой). Разные люди считают полезными разные ментальные модели. При этом я всегда ищу полезные ментальные модели.

Какие ментальные модели ваши нравятся вам больше всего?