Статьи

Применение дисциплины кодирования с помощью FindBugs

Предположим, что группа разработчиков работает параллельно над частями большого проекта. Некоторые разработчики работают над реализацией сервиса, в то время как другие работают над кодом, использующим этот сервис. Обе группы согласовали сервисный 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;)

Еще несколько ссылочных ссылок: