Почему "откровенность" считается хорошей вещью?
Я часто слышу, как люди хвалят языки, структуры, конструкции и т. Д. За то, что они "явные". Я пытаюсь понять эту логику. Цель языка, структуры и т. Д. - скрыть сложность. Если он заставляет вас явно указывать все виды деталей, то он не скрывает много сложностей, а только перемещает их. Что хорошего в явности и как вы делаете язык / инфраструктуру /API "явным", в то же время заставляя его скрывать сложность?
13 ответов
Дело не в том, что явное - это хорошо (конечно, тесно связанный многословный - плохо), а в том, что когда неявное идет не так, трудно сказать, что WTF происходит.
Взламывайте C++ в течение десяти или двух лет, и вы точно поймете, что я имею в виду.
Должны ли вы быть явными или неявными, зависит от ситуации. Вы правы в том, что часто вы пытаетесь скрыть сложность, и некоторые вещи, которые вы делаете за кулисами для вас автоматически, это хорошо. инкапсуляция и т. д.
Иногда, хотя фреймворки или конструкции скрывают от нас то, что не должны, это делает вещи менее ясными. Иногда определенная информация или настройки скрыты от нас, и поэтому мы не знаем, что происходит. Делаются предположения, которые мы не понимаем и не можем определить. Поведения случаются, что мы не можем предсказать.
Инкапсуляция: хорошо. Прятаться: плохо. Правильный вызов требует опыта. Где логика принадлежит, она должна быть явной.
Пример: однажды я удалил около 90 строк кода из серии из дюжины кодов за страницами; код доступа к данным, бизнес-логика и т. д., которые там не принадлежали. Я переместил их на базовые страницы и ключевой бизнес-объект. Это было хорошо (инкапсуляция, разделение задач, организация кода, разделение и т. Д.).
Затем я взволнованно осознал, что могу удалить последнюю строку кода со многих из этих страниц, переместив ее на базовую страницу. Это была строка, которая взяла параметр из URL и передала его бизнес-объекту. Хорошо право? Ну нет, это было плохо (я прятался). Эта логика принадлежала здесь, хотя она была почти одинаковой строкой на каждой странице. Он связал намерение пользовательского интерфейса с бизнес-объектом. Это должно быть явно. В противном случае я прятался, не заключая в капсулу. С этой строкой кто-то, глядя на эту страницу, будет знать, что эта страница делает и почему; без этого было бы больно определять, что происходит.
Я считаю, что явное относится к знанию того, что он делает, когда вы его используете. Это отличается от точного знания того, как это делается, что является сложной частью.
Речь идет о выражении намерений. Читатель не может сказать, был ли оставлен дефолт по ошибке или умышленно. Быть явным устраняет это сомнение.
Код сложнее читать, чем писать. В нетривиальных приложениях данный фрагмент кода также будет читаться чаще, чем написано. Поэтому мы должны написать наш код, чтобы сделать его максимально удобным для читателя. Код, который делает много вещей, которые не очевидны, нелегко прочитать (или, скорее, трудно понять, когда вы читаете его). Ergo, откровенность считается хорошей вещью.
Быть явным против неявного - это все, что вы скрываете, и что вы показываете.
В идеале вы раскрываете понятия, которые интересуют или интересуют пользователя (независимо от того, хотят они этого или нет).
Преимущество откровенности заключается в том, что легче отследить и выяснить, что происходит, особенно в случае сбоя. Например, если я хочу вести журнал, у меня может быть API, который требует явной инициализации с каталогом для журнала. Или я могу использовать по умолчанию.
Если я приведу явный каталог, и он потерпит неудачу, я буду знать почему. Если я использую неявный путь, и он терпит неудачу, я не буду иметь представления о том, что пошло не так, почему или где искать, чтобы это исправить.
Неявное поведение почти всегда является результатом сокрытия информации от потребителя. Иногда это правильно, например, когда вы знаете, что в вашей среде есть только один "ответ". Тем не менее, лучше знать, когда вы скрываете информацию и почему, и убедитесь, что вы позволяете своим клиентам работать ближе к их уровню намерений и не пытаться скрыть элементы существенной сложности.
Часто неявное поведение является результатом "самоконфигурирования" объектов, которые смотрят на свое окружение и пытаются угадать правильное поведение. Я бы вообще избегал этой схемы.
В целом одно правило, которому я, вероятно, следую, состоит в том, что для данного API любая операция должна быть либо явной, либо неявной, но не комбинацией. Либо сделайте операцию тем, что должен сделать пользователь, либо сделайте это чем-то, о чем им не нужно думать. Когда вы смешаете эти два, вы столкнетесь с самыми большими проблемами.
Использование поведения по умолчанию скрывает важные детали от людей, которые не очень хорошо знакомы с языком / структурой / чем угодно.
Рассмотрим, как трудно понять Perl-код, который в значительной степени опирается на сокращения, для людей, которые не знают Perl.
Каркасы и т. Д. Могут быть как явными, так и скрывать сложность, предлагая правильные абстракции для выполняемой работы.
Быть явным позволяет другим осмотреть и понять, что подразумевается под первоначальным разработчиком.
Сокрытие сложности не эквивалентно неявности. Неявность приведет к тому, что код, который будет понятен только тому, кто его написал, как попытка понять, что происходит под капотом, сродни реверс-инжинирингу в этом случае.
Явный код имеет теоретический шанс оказаться правильным. Неявный код никогда не имеет шансов в этом отношении.
Явный код является поддерживаемым, неявный код - нет, это связано с предоставлением правильных комментариев и тщательным выбором ваших идентификаторов.
"Явный" язык позволяет компьютеру находить ошибки в программном обеспечении, чего нет в менее явном языке.
Например, C++ имеет const
ключевое слово для переменных, значения которых никогда не должны изменяться. Если программа пытается изменить эти переменные, компилятор может заявить, что код, вероятно, неверен.
Хорошая абстракция не скрывает сложностей, она принимает решения, которые лучше оставить на усмотрение компилятора.
Рассмотрим сборку мусора. Сложности освобождения ресурсов делегируются сборщику мусора, который (предположительно) лучше квалифицирован для принятия решения, чем вы, программист. Это не только снимает решение с ваших рук, но и принимает лучшее решение, чем вы сами.
Явная (иногда) хорошая, потому что она делает так, что определенные решения, которые в некоторых случаях лучше оставить программисту, не принимаются автоматически менее квалифицированным агентом. Хороший пример - когда вы объявляете тип данных с плавающей запятой на языке c-type и инициализируете его целым числом:
double i = 5.0;
если вместо этого вы должны были объявить это как
var i = 5;
компилятор по праву предположит, что вы хотите использовать int, а последующие операции будут усечены.
Ясность желательна в контексте разъяснения читателю вашего кода того, что вы намеревались сделать.
Есть много примеров, но все дело в том, чтобы не оставлять никаких сомнений в своих намерениях.
Например, они не очень явные:
while (condition);
int MyFunction()
bool isActive; // In C# we know this is initialised to 0 (false)
a = b??c;
double a = 5;
double angle = 1.57;
но это:
while (condition)
/* this loop does nothing but wait */ ;
private int MyFunction()
int isActive = false; // Now you know I really meant this to default to false
if (b != null) a = b; else a = c;
double a = 5.0;
double angleDegrees = 1.57;
Последние случаи не оставляют места для неправильного толкования. Первый может привести к ошибкам, когда кто-то не может их внимательно прочитать, или он не понимает менее читаемый синтаксис для выполнения чего-либо, или смешивает целочисленные и плавающие типы.
В некоторых случаях противоположность - это "магия" - как в "тогда происходит чудо".
Когда код чтения разработчика пытается понять или отладить происходящее, явность может быть достоинством.
Цель движущихся фреймворков состоит в том, чтобы устранить дублирование в коде и упростить редактирование фрагментов, не нарушая целостности. Когда у вас есть только один способ что-то сделать, например, сказать SUM(x,y); Мы точно знаем, что это будет делать, нет причин когда-либо переписывать это, и, если нужно, можете, но это крайне маловероятно. Противоположностью этому являются языки программирования, такие как.NET, которые предоставляют очень сложные функции, которые вам часто придется переписывать, если вы делаете что-то, кроме очевидного простого примера.