Исправить обычные библиотечные функции или отказаться? - PullRequest
5 голосов
/ 18 марта 2010

Представьте, что у меня есть функция с ошибкой:

Псевдокод:

void Foo(LPVOID o)
{ 
   //implementation details omitted
}

Проблема в том, что пользователь прошел null:

Object bar = null;

...

Foo(bar);

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

Если я теперь изменю функцию на:

Псевдо-код:

void Foo(LPVOID o)
{
   if (o == null) throw new EArgumentNullException("o");

   //implementation details omitted
}

тогда люди, которые счастливо пользовались этой функцией и случайно не получили нарушения доступа, теперь внезапно начнут видеть EArgumentNullException.

Продолжаю ли я позволять людям неправильно использовать функцию и создавать новую версию функции? Или я исправляю функцию, чтобы включить то, что она должна была иметь изначально?


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


Считайте, что ошибка настолько распространена, что Microsoft пришлось ее исправлять для разработчиков:

 MessageBox(GetDesktopWindow, ...);

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

 MessageBox(HWND hWndParent, ...)
 {
    if (hWndParent == GetDesktopWindow)
       throw new Exception("hWndParent cannot be the desktop window. Use NULL instead.");

    ...
 }

На самом деле Microsoft изменила диспетчер окон, чтобы автоматически исправить неверный параметр:

 MessageBox(HWND hWndParent, ...)
 {
    if (hWndParent == GetDesktopWindow)
       hWndParent = 0;

    ...
 }

В моем вымышленном примере нет способа исправления функции - если мне не дали объект, я не могу сделать то, что мне нужно с ним сделать.

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

Ответы [ 6 ]

2 голосов
/ 18 марта 2010

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

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

1 голос
/ 18 марта 2010

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

Вы не можете поймать все. Что если кто-то напишет "MakeLocation (" Ian Boyd "," isupid ");"? Вы бы создали новую функцию или изменили бы функцию, чтобы поймать это? Нет, вы бы уволили разработчика (или, по крайней мере, накажите его).

Конечно, для этого необходимо документировать что требует ваша функция в качестве ввода.

0 голосов
/ 18 марта 2010

Это полностью зависит от вас, вашей кодовой базы и ваших пользователей.

Если вы являетесь Microsoft, и у вас есть ошибка в вашем API, которая используется миллионами разработчиков по всему миру, то вы, вероятно, захотите просто создать новую функцию и обновить документы старой. Если вы можете, вы также захотите обновить компилятор, чтобы он также выдавал предупреждения. (Хотя даже тогда вы сможете изменить существующую систему; помните, когда MS переключила VC на стандарт C ++, и вам пришлось обновить все свои #include iostream s и добавить using std s, чтобы простые, существующие консольные приложения снова работали ?)

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


Если вы небольшая компания или независимый разработчик, то обязательно исправьте эту функцию. Если вам нужно только обновить себя или нескольких человек в связи с новым использованием, то исправление этого является лучшим решением, тем более что это не имеет большого значения, потому что все, что на самом деле требуется, - это добавление примечаний к документации по функции. например, do not pass NULL или an exception is thrown if hWnd is the desktop и т. д.

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


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

Подводя итог, в вашем конкретном примере (с учетом предоставленной информации) вы должны просто исправить это.

0 голосов
/ 18 марта 2010

Два варианта:

  • Присвойте версии для проверки ошибок новое имя и не используйте старую версию (одна версия позже начнет выдавать предупреждения (время компиляции, если возможно, время выполнения, если необходимо), две версии позже удалят его).
  • [не всегда возможно] Поместите вновь введенную проверку ошибок таким образом, чтобы она запускалась только в том случае, если немодифицированная версия вылетит или выдаст неопределенное поведение. (Так что пользователи, которые заботились в своем коде, не получают неприятных сюрпризов.)
0 голосов
/ 18 марта 2010

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

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

0 голосов
/ 18 марта 2010

Это то, где автоматические тесты [модульное тестирование, интеграционное тестирование, автоматическое функциональное тестирование] хороши, они дают вам возможность изменять существующий код с уверенностью.

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

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

Итак, внесите изменения, запустите модульные тесты, а затем автоматизированные функциональные тесты. Исправьте все ошибки и ваш золотой!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...