>if (attributeExists("username")) {
> setAttribute("username", "unclebob");
> ...
>}
Используйте исключения вместо возвращения кодов ошибок
Возвращение кодов ошибок функциями-командами является неочевидным нарушением принципа разделения команд и запросов. Оно поощряет использование команд в предикатных выражениях if:
>if (deletePage(page) == E_OK)
Такие конструкции не страдают от смешения глаголов с прилагательными, но они приводят к созданию структур слишком глубокой вложенности. При возвращении кода ошибки возникает проблема: вызывающая сторона должна немедленно отреагировать на ошибку.
>if (deletePage(page) == E_OK) {
> if (registry.deleteReference(page.name) == E_OK) {
> if (configKeys.deleteKey(page.name.makeKey()) == E_OK){
> logger.log("page deleted");
> } else {
> logger.log("configKey not deleted");
> }
> } else
>{
> logger.log("deleteReference from registry failed");
> }
>} else {
> logger.log("delete failed");
> return E_ERROR;
>}
С другой стороны, если вместо возвращения кодов ошибок используются исключения, то код обработки ошибок изолируется от ветви нормального выполнения и упрощается:
>try {
> deletePage(page);
> registry.deleteReference(page.name);
> configKeys.deleteKey(page.name.makeKey());
>}
>catch (Exception e) {
> logger.log(e.getMessage());
>}
Изолируйте блоки try/catch
Блоки try/catch выглядят весьма уродливо. Они запутывают структуру кода и смешивают обработку ошибок с нормальной обработкой. По этой причине тела блоков try и catch рекомендуется выделять в отдельные функции.
>public void delete(Page page) {
> try {
> deletePageAndAllReferences(page);
> }
> catch (Exception e) {
> logError(e);
> }
>}
>private void deletePageAndAllReferences(Page page) throws Exception {
> deletePage(page);
> registry.deleteReference(page.name);
> configKeys.deleteKey(page.name.makeKey());
>}
>private void logError(Exception e) {
> logger.log(e.getMessage());
>}
В этом примере функция delete специализируется на обработке ошибок. В этой функции легко разобраться, а потом забыть о ней. Функция deletePageAndAllReferences специализируется на процессе полного удаления страницы. Читая ее, можно не обращать внимания на обработку ошибок. Таким образом, код нормального выполнения отделяется от кода обработки ошибок, а это упрощает его понимание и модификацию.
Обработка ошибок как одна операция
Функции должны выполнять одну операцию. Обработка ошибок — это одна операция. Значит, функция, обрабатывающая ошибки, ничего другого делать не должна. Отсюда следует, что если в функции присутствует ключевое слово try, то оно должно быть первым словом в функции, а после блоков catch/finally ничего другого быть не должно (как в предыдущем примере).