Здесь вы имеете дело с интерфейсом. Добавив поведение «когда ввод есть null
, инициализируйте ввод», вы фактически расширили интерфейс метода - теперь вместо того, чтобы всегда работать с действительным списком, вы заставили его «исправить» ввод. Является ли это официальной или неофициальной частью интерфейса, вы можете поспорить, что кто-то (скорее всего, включая вас) будет использовать это поведение.
Интерфейсы должны быть простыми, и они должны быть относительно стабильными, особенно в public static
методе. Вы получаете немного свободы в частных методах, особенно в методах частных экземпляров. Неявно расширяя интерфейс, вы на практике сделали свой код более сложным. Теперь представьте, что вы на самом деле не хотите использовать этот путь кода, поэтому избегайте его. Теперь у вас есть немного непроверенного кода, который притворяется, будто это часть поведения метода. И я могу вам сказать прямо сейчас, что, возможно, в нем есть ошибка: когда вы передаете список, этот список видоизменяется методом. Однако, если вы этого не сделаете, вы создаете локальныйсписок, и выбросить его позже. Это противоречивое поведение, которое заставит вас плакать через полгода, когда вы пытаетесь отследить скрытую ошибку.
Вообще, защитное программирование - довольно полезная вещь. Но пути кода для защитных проверок должны быть проверены, как и любой другой код. В таком случае они усложняют ваш код без причины, и вместо этого я бы выбрал такую альтернативу:
if (rows == null) throw new ArgumentNullException(nameof(rows));
Вы не хотите, чтобы ввод был rows
нулевым, и вы хотите, чтобы ошибка стала очевидной для всех ваших абонентов как можно скорее .
Есть много ценностей, которые вам нужно переделывать при разработке программного обеспечения. Даже надежность сама по себе является очень сложным качеством - например, я бы не посчитал вашу защиту более надежной, чем создание исключения. Исключения довольно удобны для того, чтобы дать вам безопасное место для повторной попытки из безопасного места - проблемы с повреждением данных, как правило, гораздо сложнее отследить, чем распознать проблему на ранней стадии и безопасно ее обработать. В конце концов, они, как правило, создают у вас иллюзию надежности, и затем через месяц вы замечаете, что десятая часть ваших назначений пропала, потому что вы никогда не замечали, что обновился другой список. Уч.
Удостоверьтесь, чтобы различить два. Защитное программирование - это полезный метод для выявления ошибок в месте, где они наиболее актуальны, что значительно помогает при отладке и обеспечивает хорошую обработку исключений, предотвращая «скрытую коррупцию». Ошибка рано, ошибка быстро. С другой стороны, то, что вы делаете, больше похоже на «сокрытие ошибок» - вы манипулируете вводными данными и делаете предположения о том, что имел в виду вызывающий объект. Это очень важно для кода, ориентированного на пользователя (например, проверка орфографии), но вы должны быть осторожны, когда видите код, обращенный к разработчику.
Основная проблема заключается в том, что какую бы абстракцию вы ни делали, она будет просачиваться («Я хотел напечатать снова, а не предвкушать! Глупая проверка орфографии!»), А код для обработки всех особых случаев и исправлений по-прежнему остается кодом нужно поддерживать и понимать, а код нужно тестировать. Сравните усилия, направленные на то, чтобы убедиться, что ненулевой список передан, с исправлением ошибки, которая возникла у вас год спустя, в процессе производства - это не хороший компромисс. В идеальном мире вы бы хотели, чтобы каждый метод работал исключительно со своим собственным вводом, возвращая результат и не изменяя глобального состояния. Конечно, в реальном мире вы найдете множество случаев, когда это несамое простое и ясное решение (например, при сохранении файла), но я считаю, что поддержание чистоты методов, когда у них нет причин читать или манипулировать глобальным состоянием, значительно упрощает анализ кода. Это также дает вам больше естественных точек для разделения ваших методов :)
Это не значит, что все неожиданное должно привести к сбою приложения, а наоборот. Если вы правильно используете исключения, они, естественно, образуют безопасные точки обработки ошибок, где вы можете восстановить стабильное состояние приложения и позволить пользователю продолжить то, что они делают (в идеале, избегая потери данных для пользователя). В этих точках обработки вы увидите возможности для устранения проблем («Номер заказа 2212 не найден. Вы имели в виду 2212b?») Или предоставление пользователю контроля («Ошибка подключения к базе данных. Попробуйте еще раз?»). Даже если такой опции нет, по крайней мере, это даст вам шанс, что ничего не испортилось - я начал ценить код, который использует using
и try
... finally
намного больше, чем try
...catch
Это дает вам много возможностей для поддержания инвариантов даже в исключительных условиях.
Пользователи не должны терять свои данные и работать. Это все равно должно быть сбалансировано с затратами на разработку и т. Д., Но это довольно хорошее общее руководство (если пользователи решают, покупать ваше программное обеспечение или нет - внутреннее программное обеспечение обычно не имеет такой роскоши). Даже сбой всего приложения становится намного меньшей проблемой, если пользователь может просто перезапустить и вернуться к тому, что он делал. Это настоящая надежность - Word сохраняет вашу работу все время, не повреждая документ на диске, и дает вам возможностьвосстановить эти изменения после перезапуска Word после сбоя. Это лучше, чем отсутствие ошибки в первую очередь? Вероятно, нет - хотя не забывайте, что работа, потраченная на выявление редкой ошибки, может быть лучше проведена повсюду. Но это намного лучше, чем альтернативы - например, поврежденный документ на диске, вся работа с момента последнего сохранения потеряна, документ автоматически заменяется изменениями до сбоя, которые оказались Ctrl + A и Delete.