Предположим, что группа разработчиков работает параллельно над частями большого проекта. Некоторые разработчики работают над реализацией сервиса, в то время как другие работают над кодом, использующим этот сервис. Обе группы согласовали сервисный API и начали работать отдельно с учетом предположений API.
Как вы думаете, у этой истории будет счастливый конец? Ну, … — может быть ? Есть инструменты, которые могут помочь достичь этого. Одним из таких инструментов является FindBugs , поддерживаемый JSR-305 (аннотации для обнаружения дефектов программного обеспечения).
Давайте посмотрим на контракт API сервиса:
package com.blogspot.vardlokkur.services; import java.util.List; import javax.annotation.CheckForNull; import javax.annotation.Nonnull; import com.blogspot.vardlokkur.entities.domain.Employer; /** * Defines the API contract for the employer service. * * @author Warlock * @since 1.0 */ public interface EmployerService { /** * @param identifier the employer's identifier * @return the employer having specified {@code identifier}, {@code null} if not found */ @CheckForNull Employer withId(@Nonnull Long identifier); /** * @param specification defines which employers should be returned * @return the list of employers matching specification */ @Nonnull List<Employer> thatAre(@Nonnull Specification specification); }
Как видите, к сигнатурам метода службы добавляются аннотации, такие как @Nonnull или @CheckForNull . Цель их использования — определить требования к параметрам метода (например, параметр identifier не может быть нулевым ), а ожидания значений, возвращаемых методами (например, результат метода службы, могут быть нулевыми, и вы должны проверить это в своем коде ).
Ну и что? — спросите вы, — должен ли я сам проверить их в коде или доверить коллегам, что они будут использовать руководящие принципы, определенные этими аннотациями? Конечно, нет ? — никому не доверяйте, используйте инструменты, которые проверят предположения API, такие как FindBugs .
Предположим, что у нас есть следующий сервис API:
package com.blogspot.vardlokkur.test; import org.junit.Before; import org.junit.Test; import com.blogspot.vardlokkur.services.EmployerService; import com.blogspot.vardlokkur.services.impl.DefaultEmployerService; /** * Employer service test. * * @author Warlock * @since 1.0 */ public class EmployerServiceTest { private EmployerService employers; @Before public void before() { employers = new DefaultEmployerService(); } @Test public void test01() { Long identifier = null; employers.withId(identifier); } @Test public void test02() { employers.withId(Long.valueOf(1L)).getBusinessName(); } @Test public void test03() { employers.thatAre(null); } }
Давайте попробуем проверить код в соответствии с предположениями API сервиса:
FindBugs проанализирует ваш код и переключится на перспективу FindBugs, показывая потенциальные проблемы:
Null передан для ненулевого параметра |
Возможно разыменование нулевого указателя |
Аналогичным образом, ребята, пишущие служебный код, могут проверить свою работу в соответствии с определенными предположениями API, например если вы запустите FindBugs для самой ранней версии реализации сервиса:
package com.blogspot.vardlokkur.services.impl; import java.util.List; import com.blogspot.vardlokkur.entities.domain.Employer; import com.blogspot.vardlokkur.services.EmployerService; import com.blogspot.vardlokkur.services.Specification; /** * Default implementation of {@link EmployerService}. * * @author Warlock * @since 1.0 */ public class DefaultEmployerService implements EmployerService { /** * {@inheritDoc} */ public Employer withId(Long identifier) { return null; } /** * {@inheritDoc} */ public List<Employer> thatAre(Specification specification) { return null; } }
Следующая ошибка будет найдена:
Как видите, ничто не может спрятаться от FindBugs и его союзника — JSR-305;)
Еще несколько ссылочных ссылок:
- JSR-305: аннотации для обнаружения дефектов программного обеспечения
- JSR 305: серебряная пуля или не пуля вообще?