[Перевод] Пять знаменитых цитат о программировании с объяснениями

a2ujr8shjmkgem4rcna75b86uv8.png

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

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

1. О косвенности


«Все проблемы в программировании решаются путём создания дополнительного уровня косвенности» — Дэвид Виллер


Вот вам цитата из книги Computer Science Theory and Application, которую все любят повторять и мало кто любит объяснять. Тем не менее, это одна из моих любимых программерских истин — она метко раскрывает саму суть программирования.

Самый простой способ осмыслить косвенность — представить себе слои. Ну например, представим себе, что у вас есть небольшой проект, в рамках которого нужно поместить компонент А внутрь компонента В:

jynupa5pjdaqizl5owxhwovasge.png

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

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

Многие скажут вам, что смысл программирования состоит в том, чтобы писать ясные инструкции на языке, который поймет даже самый тупой компьютер. Но цитата Дэвида Виллера предлагает более глубокий взгляд на вопрос. Быть хорошим программистом — значит подниматься по лестнице косвенности, стремясь к самым общим решениям.

Бонусная цитата в тему

Косвенность — мощный инструмент, но за сложность приходится платить. Люди редко приводят то высказывание, которое следует сразу после знаменитой цитаты:

«Обычно это создает новую проблему» — Дэвид Виллер.


Именно благодаря этой истине программисты с давних пор остаются при делах.

2. О простоте


«Простота — предпосылка надежности» — Эдсгер Дейкстра


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

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

Чтобы принять позицию Дейкстра, нам нужно изменить свое понимание того, что такое «хороший код». Это не обязательно самый лаконичный код, или самый быстродействующий, и уж точно не самый заумный. Хороший код — это код, на который можно положиться.

Бонусная цитата в тему

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

«Если мы хотим подсчитать количество строк кода, следует воспринимать их не как написанные, а как потраченные» — Эдсгер Дейкстра


3. О читабельности и переписывании


«Код сложнее читать, чем писать» — Джоэль Спольски


На первый взгляд, эта цитата Джоэля Спольски, легенды программирования и сооснователя Stack Overflow, кажется разумной, но обманчиво поверхностной. Да, фрагменты кода бывают информационно насыщенными, излишне сжатыми или утомительно длинными. И это относится не только к тому, что писали другие люди. Если вы посмотрите на свои собственные прошлогодние труды, вам понадобится какое-то время, чтобы воссоздать логику, которую вы когда-то знали от и до.

Но наблюдение Спольски разворачивается в нечто интересное. Опасность кода, который с трудом читается, состоит не только в самых очевидных последствиях (его тяжело корректировать и совершенствовать). Есть и другая, большая опасность: сложный для восприятия код кажется хуже, чем есть на самом деле. Фактически, разбираться в чужом коде может показаться такой непосильной задачей, что у вас возникнет искушение совершить то, что Спольски называет грубейшей из всех ошибок — переписать все заново.

Я не говорю, что архитектура системы никогда не выигрывает от подобных переписываний. Разумеется, бывает, что и выигрывает. Но улучшение такого рода дорого обходится. Во всем, что касается тестирования и устранения багов –, а это две составляющие разработки, которые отнимают больше времени, чем собственно написание кода — вы возвращаетесь на исходную позицию. Переписывание выглядит заманчиво, потому что укладывается в одно из самых распространенных заблуждений разработчиков — склонность недооценивать трудозатраты на концептуально простые вещи. Именно поэтому 50% времени уходит на заключительные 5% проекта. Элементарные задачи могут отнимать на удивление много времени! А решение проблемы, которую уже решал в прошлом, всегда выглядит проще простого.

Ладно, если переписывать все с нуля, чтобы довести код до совершенства, не следует, то какие есть более удачные альтернативы? Ответ: привлечь каждого разработчика к процессу непрерывного фрагментарного рефакторинга. Так ваш код совершенствуется постоянно, за счет цепочки небольших изменений — реальная выгода с минимальными рисками. Читабельность можно повышать по ходу дела.

Бонусная цитата в тему

Если вы все еще сомневаетесь в важности читабельности, Мартин Фаулер поможет взглянуть на проблему шире:

«Любой дурак может писать код, который будет понятен компьютерам. Хорошие программисты пишут код, который будет понятен людям» — Мартин Фаулер


Иными словами, задача программиста — выдать не просто рабочий код, но код с внутренней логикой.

4. О повторениях


«Не повторяйтесь. Каждый фрагмент знания должен иметь единственное, однозначное, надежное представление в системе» — Энди Хант и Дэвид Томас


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

sz3xnyu5f8bal09cop15f3h8urg.png

Этого бага можно было бы избежать с методом GetTeamUniform()

Однако повторы сеют хаос не только в коде. Данная версия хорошо всем известного принципа DRY (Don«t Repeat Yourself / Не потворяйтесь) толкует принцип устранения дубликатов расширительно, охватывая и другие места, куда могут пробраться повторы. Сейчас разговор идет уже не о дубликатах в коде — мы говорим в том числе и о повторах в масштабах всей системы. А системы кодируют знания в различных форматах. В частности это:

  • Операторы
  • Комментарии к коду
  • Документация для разработчиков или клиентов
  • Схемы данных (например, таблицы базы данных)
  • Прочие спецификации — планы тестирования, документы по организации процессов, правила сборки


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

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

Бонусная цитата в тему

Возможность того, что код и комментарии к нему вступят в противоречие друг с другом, породила оживленные дискуссии: чего вообще больше от комментариев — пользы или вреда? Сторонники экстремального программирования относятся к ним с откровенным недоверием.

«Код никто не лжет, а вот с комментариями такое случается» — Рон Джеффрис


5. О сложных проблемах


«В компьютерных науках есть только две сложные проблемы — аннулирование кэша и придумывание названий» — Фил Карлтон


С виду эта цитата кажется просто программисткой шуткой, забавной, но ничем не выделяющейся из прочих. Каждый может прочувствовать контраст между чем-то, что звучит как сложная задача (аннулирование кэша), и чем-то, что звучит как сущий пустяк (придумывание названий). Любой программист хоть раз убивал целые часы на какую-нибудь до смешного мелкую проблему — два параметра, проставленных не в том порядке, переменную, которая где-то с большой буквы, а где-то нет (спасибо, JavaScript!). Пока людям для достижения своих целей приходится работать совместно с компьютерами, программирование всегда будет представлять собой смесь высокоуровневого системного планирования и дурацких опечаток.

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

Существует много разновидностей плохих названий. Все мы встречались с переменными, которые нарекли в честь типов данных (myString, obj), сокращений (pc, то есть product catalog), какой-нибудь незначительной детали имплементации (swappable_name, formUserInput) или же вообще оставили безымянными (ret_value, tempArray). Легко попасться в ловушку и назвать переменную исходя из того, что вы сейчас с ней делаете, а не из ее содержимого. А со значениями логических типов данных вообще беда: что подразумевает progress — что прогресс уже начался, что нужно отобразить информацию о прогрессе в интерфейсе или вообще что-то третье?

plnrcpbzaxquhg6lv_gu_acosoa.jpeg

Источник: CommitStrip.com

Перевод

«results_tmp_2? Это что еще за?… Ты что, весь мир ненавидишь? Нельзя так называть переменные!» — «Ну, мне нужно было на время сохранить результаты запроса… И я уже один раз так делал, вот и получается results_tmp_2. Стараюсь не пренебрегать семантикой»


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

Бонусная цитата в тему

«В компьютерных науках есть только три сложные проблемы — аннулирование кэша, придумывание названий и ошибка на единицу» — Леон Бамбрик

© Habrahabr.ru