Здравствуйте, silart, Вы писали:
S>Просто мне нужно было документировать каждый метод на предмет генерирования исключений. Проект уже большой и начинаешь забывать что генерит какая функция. Все типы исключений в проекте унаследованы от одного базового класса. А каждый класс создает свой тип исключений, наследник базового (это вложенный класс). И когда один класс имеет поля другого класса, а другой третьего, и т. д. в конечном счете класс верхнего уровня генерит много типов исключений. Но все они имеют общий базовый тип. S>Как вы считаете, такой подход хорошь, или есть что то лучше?
Такой подход ужасен!!!
Намного лучше иметь каку-то продуманную систему исключений, и ей пользоваться.
В частности в ней можно иметь такое исключение, которое параметризуется специальм объектом, которы описывает контекст исключения (например комментом, или ссылкой на строку/файл, или дампом каких-то переменных, или ещё как)
Ещё можно предусмотреть возможность сравнивать такое параметризованное исключение с объектом-параметром, чтобы выяснить то не то. Можно приделать систему трансляции в коды, систему итерации имеющихся в программе исключений и т. д.
class CErrorDescription {
// тут конструктор от описания. Например от строчки, которая является ID и
// строчки, которая содержит совет пользователю как поправить ситуацию
};
Ну то есть что-то типа:
class MyGeneralException {
// тут что-то, например функция, проверяющая, что эта ошибка соответсвует CErrorDescription
};
class MyFileException : public MyGeneralException{
// тут что-то на тему о файлах
};
class MyErrorException : public MyGeneralException {
// тут конструктор от CErrorDescription;
};
// Ну и т. д.
потом пишешь типа
extern CErrorDescription MyDictionaryOverflow;
// где-то в работе со словарём пишешь так:void add_word( const char* word )
{
if(is_dic_owerflow() ) // для этого удобно завести функцию или макрос. Например CheckErrorthrow MyErrorException( MyDictionaryOverflow, get_dictionary_name() );
// тут код
}
А где-то снаружи, пишешь:
void do_it( const char* text )
{
try {
// тут вызов какой-то обработки, в том чисели и add_word
} catch( MyGeneralException& e ) {
if( e.IsItOneOf( MyDictionaryOverflow ) ) {
// тут какая-то обработка.
} else {
throw;
}
}
}
S>Спасибо dip_2000. Я посмотрю Саттера.
Тоже не помешает...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Намного лучше иметь каку-то продуманную систему исключений, и ей пользоваться. E>В частности в ней можно иметь такое исключение, которое параметризуется специальм объектом, которы описывает контекст исключения (например комментом, или ссылкой на строку/файл, или дампом каких-то переменных, или ещё как)
Здравствуйте, dip_2000, Вы писали:
_>Я бы выбрал 2-й. А лучше 2-й с исчерпывающим комментарием перед объявлением функции
В скором времени твои комментарии устареют и не будут значить ничего кроме шума. Представь как ты введешь новое исключение в какой-либо простой функции, которая зовется из десятка других функций, которые зовутся из третьих функций и т.д. Безошибочно обновить комментарии во всех задействованных функциях будет практически невозвожно.
Здравствуйте, Erop.
Вы меня не совсем так поняли. У меня примерно такой же подход, что и у вас. Т. е. общий базовый класс исключений, реализованный в отдельном хидере. Он хранит комментарий, название функции, сгенерировавшей исключение, файл, строка, код ошибки. А каждый класс (или почти каждый, главное чтоб он был достаточно крупным) определяет свой потомой от базового класса исключений. Причем этот потомок является вложенным классом. Все остальные вложенные классы используют этот тип исключений. Получается что пользователь класса может обработать исключения, если в данном контексте он может это сделать, или ничего не обрабатывать. А на самом верху иерархии все исключения отлавливаются по БАЗОВОМУ типу исключений. Так что ни одно исключение не пройдет мимо.
Насчет буста надо разобраться. Просто честно говоря руки не доходят до всего, че там есть. Я в своем проекте использую сигналы, смартпоинтеры, биндеры и преобразователи типов. Может быть я заменю свой базовый тип бустовским типом.
Ниже приводится мой базовый класс исключений.
/**
Реализует базовый тип исключения.\n
*/
class x_Ception
{
public:
enum Codes
{
ERROR_OPERATION = 1,
ERROR_PARAMS = 2,
};
private:
std::string Msg; ///< Сообщение об ошибке.
std::string Func; ///< Название функции в которой сгенерировано исключение.
std::string File; ///< Название файла в которой сгенерировано исключение.
int Line; ///< Номер строки, в которой сгенерировано исключение.
int Code; ///< Код ошибки.
static std::string CutFilename(std::string fn)
{
size_t s = fn.rfind('\\');
if (s != std::string::npos)
fn.replace(0, s + 1, "");
return std::string(fn);
}
public:
x_Ception(const std::string& msg,
const std::string& func,
const std::string& file,
const int line,
const int code) :
Msg(msg), Func(func), File(CutFilename(file)), Line(line), Code(code)
{}
x_Ception(const std::string& msg,
const std::string& func,
const std::string& file,
const int line) :
Msg(msg), Func(func), File(CutFilename(file)), Line(line), Code(0)
{}
x_Ception(const std::string& msg,
const std::string& func) :
Msg(msg), Func(func), Line(0), Code(0)
{}
x_Ception(const std::string& msg) :
Msg(msg), Line(0), Code(0)
{}
virtual ~x_Ception()
{}
std::string what() const
{
std::ostringstream os;
os << Msg << ", " << Func << ", " << File << ", " << Line << " ln.";
return os.str();
}
std::string whatMessage() const
{
return Msg;
}
int whatCode() const
{
return Code;
}
std::string whereError() const
{
std::ostringstream os;
os << Func << ", " << File << ", " << Line << " ln.";
return os.str();
}
std::string whereFunction() const
{
std::ostringstream os;
os << Func;
return os.str();
}
};
Здравствуйте, silart, Вы писали:
S>Вы меня не совсем так поняли. У меня примерно такой же подход, что и у вас. Т. е. общий базовый класс исключений, реализованный в отдельном хидере. Он хранит комментарий, название функции, сгенерировавшей исключение, файл, строка, код ошибки. А каждый класс (или почти каждый, главное чтоб он был достаточно крупным) определяет свой потомок от базового класса исключений. Причем этот потомок является вложенным классом. Все остальные вложенные классы используют этот тип исключений. Получается что пользователь класса может обработать исключения, если в данном контексте он может это сделать, или ничего не обрабатывать. А на самом верху иерархии все исключения отлавливаются по БАЗОВОМУ типу исключений. Так что ни одно исключение не пройдет мимо.
Ну я собственно не понимаю, зачем нужно знать в каком классе произошло исключение.
У тебя же логика программы не на исключениях работает? То есть исключение -- это какая-то нестандартная ситуация.
Ну нестандартные ситуации они могут быть конечно какие-то очень очень специфические, но это редкость. Обычно они какие-то стандартные.
Ну типа "запрос невыполним", "есть какая-то проблема, которую может исправить или хотя бы понять пользователь", "есть какая-то проблема, которую пользователь фиг поборет".
У второй категории может быть подкатегория "ошибки файловой системы" или "ошибки взаимодействия по сети", например.
Ну там "не читается файл" или "связь порвалась", например.
Ты же, когда с каким-то классом работаешь, то тебе наверное всё равно в нём самом что-то сломалось, или в чём-то что он из себя позвал? Главное что сломалось...
Вот я тебя понял так:
class MyStatisticsCollector {
public:
class x_Ception : public ::x_Ception {
// тут чего-то ещё
};
// тут какие-то методы.
};
class MyDataProcessor {
public:
class x_Ception : public ::x_Ception {
// тут чего-то ещё
};
// тут какие-то методы.
// В том числе и такой:int GetDataQuility() const
{
MyStaticticsCollector dst;
for_each_data( curData ) {
if( !curData->IsValid() )
THROW_X_CEPTION( "Invalid data detected" );
dst.AddToStatistics( curData->SomeParam() );
}
return dst.GetDispersion();
}
};
// и теперь я пишу клиента:bool CompareData( const MyDataProcessor &left, const MyDataProcessor &right )
{
try {
return left.GetDataQuility() < right.left.GetDataQuility();
} catch( x_Ception& e ) {// Какие исключения тут ждать?
// тут обработка
}
}
Вот какие исключения ловить в клиентском коде? А если реализация изменится? И там в потрохах начнут ещё какой-нибудь класс использовать? Весь клиентский код переписывать?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Duncan MacLeod, Вы писали:
DM>В скором времени твои комментарии устареют и не будут значить ничего кроме шума. Представь как ты введешь новое исключение в какой-либо простой функции, которая зовется из десятка других функций, которые зовутся из третьих функций и т.д. Безошибочно обновить комментарии во всех задействованных функциях будет практически невозвожно.
-Я не слышу конструктивных предложений
— Я то же их не слышу!
(с) 12 стульев.
Не соответствующие действительности комментарии, и изменения в коде без соответствующих корректировок комментариев, это может да же хуже, чем явная спецификация исключений функции.
Здравствуйте, Duncan MacLeod, Вы писали:
DM>Речь идет не о намеренном несоответствии комментариев коду, а о том, что поддерживать код и комментарии в строгом соответствии при таком подходе очень сложно.
Да, я вас понял. Но у нас, например, тот кто изменяет код, сопровождаемый комментариями, отвечает за "актуальность" комментариев.
А вобще, вспомнилась глава из Страуструппа про комментарии Так вот он там пишет, что не соответствующие действительности комментарии — это еще хуже чем их отсутствие Думается он очень прав
Так что изменение откомментированного кода, без изменения соответствующих комментариев — очень плохой стиль.
А если возвращаться к первоначальному вопросу — то вопрос был, "как лучше писать, что бы код был легко поддерживаемым", я и высказал свою тз на вопрос. А дальше пошел вопрос "как лучше писать, что бы не смогли сломать". имхо если нет единых правил и требований к написанию, и внесению изменений изменений в уже написанный код — сломают все-равно.
Здравствуйте, Аноним, Вы писали:
А>Егог, вот как я обычно делаю:
А>
А>class MyDataProcessor {
А>public:
А> // У каждого класса индивидуальный тип исключений, производный от базового
А> class DPError : public ::x_Ception {
А> // тут чего-то ещё
А> };
А>};
А>
Это всё я понял, просто я nested класс иключения назвал x_Ception. По идее можно, а код легко переиспользовать зато.
А>
А>// непосредственный клиент. не очень высокий уровень
А>bool CompareData( const MyDataProcessor &left, const MyDataProcessor &right )
А>{
А> // Пытаемся обработать в этом контексте
А> try {
А> return left.GetDataQuility() < right.left.GetDataQuility();
А> } catch( MyDataProcessor::DPError& e ) {// Какие исключения тут ждать?
А> // тут обработка
А> }
А>}
А>
А зачем так делать? Если параметры не те, что какая тут обработка? А если там что-то нетривильное предполагается, то почему бы логику не написать явно?
Ну типа там, положим мы хотим вводить данные пока они не станут корректными, ну так и пишем:
MyData data;
do {
data.AskFromUser();
} while( !dataProc.IsCorrect( data ) );
dataProc.ProcessData( data );
Казалось бы так намного прямее...
А>
А>// Где-то на самом верху
А> try {
А> // вызов функции (мы не знаем, что она сгенерит, но полюбому что-то производное от x_Ception)
А> call_method();
А> } catch( x_Ception& e )
А> {
А> // тут обработка
А> }
А>
А>все это нужно, чтобы на относительно низком уровне можно было идентифицировать источник исключения. А>Тогда как на самом верху мы будем ловить базовый класс.
А зачем его идентифицировать? Обычно надо не источник идентифицировать а какую-то конкретную проблему. И для неё можно использовать какое-то конкретное решение. А в общем случае не ясно зачем идентифицировать источник. А если источник не сам класс, а используемый им класс?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Left2, Вы писали:
L>>>Кстати, а зачем вызывающему коду знать какие именно исключения может бросать функция? E>>Ну, напрмиер, чтобы их все перекрыть.. L>Перехватывать нужно те исключения, которые можешь обработать, а не те которые может швырнуть вызываемый код.
Понятие "обработать" включает в себя также преобразование пойманного исключения в свое, возможно с добавлением контекстной информации.
Здравствуйте, уважаемые.
Я пользуюсь компилятором C++ MSVS2005. Но почему-то этот компилятор выдает warning, если методе написать спецификацию исключения.
warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
Вот пример:
class My
{
public:
class Error {};
void Calculate() throw(Error)
{
...
throw Error(...);
}
};
Кто-нибудь сталкивался с такой проблемой?
В MSDN смотрел, че-то так и не понял. может ключ компиляции какой надо включить?
S>В чем собственно проблема? Почему компилер ругается?
Видимо потому, что у него есть всего два внутренних состояния для функции: может бросать исключение и не может.
Здравствуйте, silart, Вы писали:
S>Кто-нибудь сталкивался с такой проблемой? S>В MSDN смотрел, че-то так и не понял. может ключ компиляции какой надо включить?
Это связано с тем, что студия не до конца следует стандарту в этом вопросе. А именно не поддерживает спецификацию типа исключения которое может кинуть функция. Это конечно не очень хорошо, но не смертельно. Почему не смертельно — читайте у Саттера. Он вобще крайне не рекомендует писать спецификацию исключений у функций в с++.
Здравствуйте, dip_2000, Вы писали:
_>Это связано с тем, что студия не до конца следует стандарту в этом вопросе. А именно не поддерживает спецификацию типа исключения которое может кинуть функция. Это конечно не очень хорошо, но не смертельно. Почему не смертельно — читайте у Саттера. Он вобще крайне не рекомендует писать спецификацию исключений у функций в с++.
Спасибо всем, за советы. Я просто закомментировал спецификацию исключений: // throw(Error)
Просто мне нужно было документировать каждый метод на предмет генерирования исключений. Проект уже большой и начинаешь забывать что генерит какая функция. Все типы исключений в проекте унаследованы от одного базового класса. А каждый класс создает свой тип исключений, наследник базового (это вложенный класс). И когда один класс имеет поля другого класса, а другой третьего, и т. д. в конечном счете класс верхнего уровня генерит много типов исключений. Но все они имеют общий базовый тип.
Как вы считаете, такой подход хорошь, или есть что то лучше?
Здравствуйте, silart, Вы писали:
S> Я просто закомментировал спецификацию исключений: // throw(Error) S>Просто мне нужно было документировать каждый метод на предмет генерирования исключений. Проект уже большой и начинаешь забывать что генерит какая функция. Все типы исключений в проекте унаследованы от одного базового класса. А каждый класс создает свой тип исключений, наследник базового (это вложенный класс). И когда один класс имеет поля другого класса, а другой третьего, и т. д. в конечном счете класс верхнего уровня генерит много типов исключений. Но все они имеют общий базовый тип. S>Как вы считаете, такой подход хорошь, или есть что то лучше?
согласен с Егор'ом, но если спуститься с небес идеальности на грешную землю вашего проекта, то из 3-х вариантов (далее везде в функции bar() кидается исключение):
// 1class Foo
{
void Bar() throw(int);
};
//2class Foo
{
void Bar() //throw(int);
};
//3class Foo
{
void Bar(); // ничего не написано, да же этого
};
Я бы выбрал 2-й. А лучше 2-й с исчерпывающим комментарием перед объявлением функции
S>Спасибо всем, за советы.
Здравствуйте, silart, Вы писали:
S>Здравствуйте, уважаемые. S>Я пользуюсь компилятором C++ MSVS2005. Но почему-то этот компилятор выдает warning, если методе написать спецификацию исключения. S>warning C4290: C++ exception specification ignored except to indicate a function is not __declspec(nothrow)
Ну дак в MSDN-не же написано:
function is declared using exception specification, which Visual C++ accepts but does not implement. Code with exception specifications that are ignored during compilation may need to be recompiled and linked to be reused in future versions supporting exception specifications.
Т.е. MSVC увидев exception specification парсит его в соответствии со стандартом, но соответствующего поведения не реализует.
Андрей Коростелев! А ты с чем собственно не согласен?
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Андрей Коростелев! А ты с чем собственно не согласен?
Во-первых с категоричиным
Такой подход ужасен!!!
Такой подход совсем не так плох и вполне сносно масштабируется при росте количества классов исключений, потому как наличие общей базы позволяет пользователю словившему исключение специально обрабатывать только интересующее его подмножество исключений, а для остальных использовать обработчик по-умолчанию.
Во-вторых свои классы исключений как правило лучше наследовать от std::exception. Хотя бы для того, чтобы дать пользователю возможность стандартной обработки ошибок по умолчанию.
Здравствуйте, Андрей Коростелев, Вы писали:
АК>Такой подход совсем не так плох и вполне сносно масштабируется при росте количества классов исключений, потому как наличие общей базы позволяет пользователю словившему исключение специально обрабатывать только интересующее его подмножество исключений, а для остальных использовать обработчик по-умолчанию.
Ну обычно программы всё-таки в основном работают, а не исключения обрабатывают. Так что от системы исключений требуется продуманность, простота, и надёжность.
Зачем в каждом классе заводить своё исключение?
АК>Во-вторых свои классы исключений как правило лучше наследовать от std::exception. Хотя бы для того, чтобы дать пользователю возможность стандартной обработки ошибок по умолчанию.
А я с этим и не спорил...
Хотя это уже зависит от того фреймворка, который используется в проекте. Если STL, то от std::exception, а если MFC, например, то от тамошнего исключения...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Посмотрел я тут свой буст и не обнаружил в нем файла
#include <boost/exception.hpp>.
У меня версия 1.33.1. Новую нужно качать? Эту я с полгода назад скачивал.
Re[9]: название класса улыбнуло
От:
Аноним
Дата:
29.11.07 08:55
Оценка:
Егог, вот как я обычно делаю:
class MyDataProcessor {
public:
// У каждого класса индивидуальный тип исключений, производный от базовогоclass DPError : public ::x_Ception {
// тут чего-то ещё
};
// тут какие-то методы.
// В том числе и такой:int GetDataQuility() const
{
MyStaticticsCollector dst;
for_each_data( curData ) {
if( !curData->IsValid() )
throw DPError( "Invalid data detected" );
dst.AddToStatistics( curData->SomeParam() );
}
return dst.GetDispersion();
}
};
// непосредственный клиент. не очень высокий уровеньbool CompareData( const MyDataProcessor &left, const MyDataProcessor &right )
{
// Пытаемся обработать в этом контекстеtry {
return left.GetDataQuility() < right.left.GetDataQuility();
} catch( MyDataProcessor::DPError& e ) {// Какие исключения тут ждать?
// тут обработка
}
}
// Где-то на самом верхуtry {
// вызов функции (мы не знаем, что она сгенерит, но полюбому что-то производное от x_Ception)
call_method();
} catch( x_Ception& e )
{
// тут обработка
}
все это нужно, чтобы на относительно низком уровне можно было идентифицировать источник исключения.
Тогда как на самом верху мы будем ловить базовый класс.
Здравствуйте, dip_2000, Вы писали:
_>Не соответствующие действительности комментарии, и изменения в коде без соответствующих корректировок комментариев, это может да же хуже, чем явная спецификация исключений функции.
Речь идет не о намеренном несоответствии комментариев коду, а о том, что поддерживать код и комментарии в строгом соответствии при таком подходе очень сложно.
Здравствуйте, dip_2000, Вы писали:
_>Да, я вас понял. Но у нас, например, тот кто изменяет код, сопровождаемый комментариями, отвечает за "актуальность" комментариев.
Да просто при таком подходе то, какие исключения стоит ждать из функции зависит от реализации самой функции и всего того, что она при реализации использует.
То есть при любом изменении может понадобится переписать почти все комментарии.
Вот представь, что ты решил использовать новый аллокатор в перекрытом operator new, скажем...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
E>Ну обычно программы всё-таки в основном работают, а не исключения обрабатывают. Так что от системы исключений требуется продуманность, простота, и надёжность. E>Зачем в каждом классе заводить своё исключение?
Java-style
Не подумайте что я ругаю джаву — просто обычно так пишут люди, которые какое-то время писАли на Java а потом вернулись (или пересели) на С++. Дело в том что при внешней схожести спецификации исключений в Java и C++ ведут себя очень сильно по-разному.
S>Спасибо всем, за советы. Я просто закомментировал спецификацию исключений: // throw(Error) S>Просто мне нужно было документировать каждый метод на предмет генерирования исключений. Проект уже большой и начинаешь забывать что генерит какая функция. Все типы исключений в проекте унаследованы от одного базового класса. А каждый класс создает свой тип исключений, наследник базового (это вложенный класс). И когда один класс имеет поля другого класса, а другой третьего, и т. д. в конечном счете класс верхнего уровня генерит много типов исключений. Но все они имеют общий базовый тип. S>Как вы считаете, такой подход хорошь, или есть что то лучше?
Кстати, а зачем вызывающему коду знать какие именно исключения может бросать функция?
Здравствуйте, Left2, Вы писали:
L>Кстати, а зачем вызывающему коду знать какие именно исключения может бросать функция?
Ну, напрмиер, чтобы их все перекрыть..
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
L>>Кстати, а зачем вызывающему коду знать какие именно исключения может бросать функция?
E>Ну, напрмиер, чтобы их все перекрыть..
Э... catch(...) (а потом (обязательно!) — throw()). Но это всё равно имхо хыбна практика (кроме случая когда исключения не могут проходить через границы нашей функции). Перехватывать нужно те исключения, которые можешь обработать, а не те которые может швырнуть вызываемый код.
Здравствуйте, Left2, Вы писали:
E>>Ну, напрмиер, чтобы их все перекрыть.. L>Э... catch(...) (а потом (обязательно!) — throw()). Но это всё равно имхо хыбна практика (кроме случая когда исключения не могут проходить через границы нашей функции). Перехватывать нужно те исключения, которые можешь обработать, а не те которые может швырнуть вызываемый код.
Ну вот поэтому catch(...) Не годится...
Чтобы перекрыть иключения и как-то осмысленно обработать нужен их список...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
_>>Да, я вас понял. Но у нас, например, тот кто изменяет код, сопровождаемый комментариями, отвечает за "актуальность" комментариев. E>Да просто при таком подходе то, какие исключения стоит ждать из функции зависит от реализации самой функции и всего того, что она при реализации использует. E>То есть при любом изменении может понадобится переписать почти все комментарии.
А какие есть альтернативы ? Я понимаю проблемму, о которой вы говорите, я согласен, что она существует, но какие альтернативы ? Явно указывать спецификацию исключений с помощью средств языка ? Писать не документированный код ?
E>Вот представь, что ты решил использовать новый аллокатор в перекрытом operator new, скажем...
Не ежедневная операция
Здравствуйте, dip_2000, Вы писали:
_>А какие есть альтернативы ? Я понимаю проблемму, о которой вы говорите, я согласен, что она существует, но какие альтернативы ? Явно указывать спецификацию исключений с помощью средств языка ? Писать не документированный код ?
Ну, возможно, писать в комментариях дату последней проверки их валидности
Или считать что везде может пролететь x_Ception, или ещё как. Я так понимаю, что ты спрашиваешь в реалиях обсуждаемого проекта?
Ясно, что последовательный подход состоит в том, что надо перейти на нормальную систему исключений. Но это может быть очень дорого. Возможно её можно как-то регуляризировать, например. Или можно как-то переходить постепенно, или ещё чего можно. Не видя проекта не скажешь
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском