Откровенно говоря, это компромиссное решение. Пользователям, которым не нравится, что сообщения об ошибках поставляет класс ArgsException, придется написать собственную реализацию.
К этому моменту мы уже вплотную подошли к окончательному решению, приведенному в начале этой главы. Завершающие преобразования остаются читателю для самостоятельных упражнений.
Заключение
Заставить код работать недостаточно. Работоспособный код часто несовершенен. Программисты, которые заставляют свой код работать и на этом считают свою задачу выполненной, ведут себя непрофессионально. Возможно, они опасаются, что у них не хватит времени для совершенствования структуры и архитектуры кода, но я не могу с этим согласиться. Ничто не оказывает настолько всестороннего и длительного отрицательного влияния на судьбу программного проекта, как плохой код. Плохой график можно переделать, плохие требования можно переопределить. Плохую динамику рабочей группы еще можно исправить. Плохой код загнивает и разбухает, превращаясь в беспощадный груз, который тянет группу ко дну. Сколько раз я видел, как работа заходит в тупик по одной причине: в спешке вместо добротного кода создавалась какая-то безобразная мешанина, которая после этого обрекала группу на бесконечные мучения.
Конечно, плохой код можно вычистить. Но это обходится очень дорого. В процессе загнивания кода модули постепенно проникают друг в друга, образуется множество скрытых и запутанных зависимостей. Поиск и разрыв старых зависимостей — длительная, тяжелая работа. С другой стороны, поддерживать чистоту в коде относительно несложно. Если утром вы устроили беспорядок в модуле, то его будет легко вычистить днем. Или еще лучше, если вы устроили беспорядок пять минут назад, то его будет очень легко вычистить прямо сейчас.
Итак, постоянно следите за тем, чтобы ваш код оставался как можно более простым и чистым. Не допускайте, чтобы он начал загнивать.
Глава 15. Внутреннее строение JUnit
JUnit — одна из самых известных инфраструктур для языка Java. Как и положено нормальной инфраструктуре, она концептуально проста, точна в определениях и элегантна в реализации. Но как выглядит ее код? В этой главе мы покритикуем пример, взятый из инфраструктуры JUnit.
Инфраструктура JUnit
У JUnit много авторов, но все началось с совместного перелета Кента Бека и Эрика Гамма в Атланту. Кент хотел освоить Java, а Эрик собирался заняться изучением тестовой инфраструктуры Кента для языка Smalltalk. «А что может быть более естественным для двух „технарей“, запертых в тесном пространстве, чем достать портативные компьютеры и взяться за программирование?[70]» За три часа «высотной работы» были написаны основы JUnit.
Модуль, который мы рассмотрим в этой главе, предназначен для выявления ошибок сравнения строк. Он называется ComparisonCompactor. Получив две различающиеся строки (например, ABCDE и ABXDE), он выдает сводку различий между ними, генерируя строку вида <...B[X]D...>.
Я мог бы объяснить и подробнее, но тестовые сценарии сделают это лучше. Просмотрите листинг 15.1 и вы отлично поймете требования этого модуля. А заодно критически проанализируйте структуру тестов. Нельзя ли упростить их, сделать более наглядными?
package junit.tests.framework;
import junit.framework.ComparisonCompactor;
import junit.framework.TestCase;
public class ComparisonCompactorTest extends TestCase {
public void testMessage() {
String failure= new ComparisonCompactor(0, "b", "c").compact("a");
assertTrue("a expected:<[b]> but was:<[c]>".equals(failure));
}
public void testStartSame() {
String failure= new ComparisonCompactor(1, "ba", "bc").compact(null);
assertEquals(«expected: but was:», failure);
}
public void testEndSame() {
String failure= new ComparisonCompactor(1, "ab", "cb").compact(null);
assertEquals("expected:<[a]b> but was:<[c]b>", failure);
}
public void testSame() {
String failure= new ComparisonCompactor(1, "ab", "ab").compact(null);
assertEquals("expected:
}
public void testNoContextStartAndEndSame() {