Статьи

JSR 305 и проектирование по контракту


Инструменты статического анализа стали обычным явлением среди многих проектов Java.
Их практичность неоспорима, и если вы в настоящее время не используете их в своих проектах, вам определенно следует обратить на это внимание.

Однако цель этого поста — не диктовать моим читателям, как им следует выполнять свои программные проекты, а скорее дать краткий обзор недавно предложенного запроса спецификации Java. Цель JSR 305 — предложить Java-разработчику набор аннотаций, чтобы сделать инструменты статического анализа более интеллектуальными.

Кроме того, если вы еще не слышали об инструментах статического анализа, таких как FindBugs или даже JSR305, и заинтересованы в том, чтобы узнать о них больше, прежде чем читать этот пост, я предлагаю вам ознакомиться с Google Tech Talk Уильяма Пью (создателя FindBugs) на JSR 305. Эта презентация поможет прояснить, что этот JSR пытается выполнить, и может больше познакомить вас с тем, что пытаются сделать инструменты статического анализа.

Продолжая, почему инструменты статического анализа все равно нуждаются в помощи? Разве эти инструменты не должны быть достаточно сложными, чтобы определить, что является ошибкой? Хотя эти инструменты довольно мощные, они далеки от совершенства и часто называют вопрос к коду совершенно правильным. Этот JSR является попыткой помочь решить эти проблемы, и я считаю, что этот JSR также поможет разработчикам определить контракты для своих исполнителей.

Многие языки, такие как Eiffel, построены на основе теории дизайна по контракту. Проектирование по контракту — это подход к разработке программного обеспечения, который позволяет разработчикам строго определять набор инвариантов и спецификаций для классов и объектов. Если вы заинтересовались этой темой, я отсылаю вас к удивительной книге Бертрана Мейера («Проектирование по контракту» и «Язык программирования Eiffel») «Создание ориентированного программного обеспечения».

По моему мнению, любой проект может извлечь выгоду из адаптации некоторых или всех идей из Design by Contract, и это не обязательно требует много работы.

Теперь, когда я отступил от своего первоначального положения, давайте кратко рассмотрим, что JSR305 приносит с точки зрения аннотаций. Я предполагаю, что вы уже знакомы с JSR305 и аннотациями на Java.

Текущее предложение, помните, что это все еще в стадии разработки, включает аннотации для Nullness, Sign, Return type & Purity, Taint, Language и Threading. Каждая из этих аннотаций должна помочь разработчику четко определить допустимые состояния для методов и переменных в их классах, чтобы такие инструменты, как FindBugs, могли с уверенностью выявлять нарушения.

Эти аннотации также работают для того, чтобы доставлять автоматическую документацию программного обеспечения непосредственно из Проекта по контракту, поскольку они помогают разработчику четко определить набор допустимых состояний, на которые могут ссылаться разработчики при использовании своего кода. Теоретически эти аннотации могут также использоваться IDE для предупреждения разработчиков и разработчиков, если они нарушают какое-либо из этих состояний.

Давайте рассмотрим фрагмент кода Eiffel как пример того, как на самом деле работает Design by Contract, и как JSR305 поможет достичь чего-то похожего в Java. В следующем примере приведен простой класс счетчика, который позволяет увеличивать, уменьшать и сбрасывать счетчик. Класс счетчика, однако, имеет набор допустимых состояний, которые он должен поддерживать.

Во-первых, счетчик никогда не должен быть меньше нуля. Это важно, так как разработчик может создать экземпляр этого класса и вызвать функцию декремента, ведущую к странному поведению. Во-вторых, приращение и уменьшение должны каким-то образом изменять состояние счетчика, либо уменьшая его, либо увеличивая его. Функция декремента также имеет третье требование, чтобы счетчик не был равен нулю перед вызовом этой функции.

indexing
description: "Counters that you can increment by one, decrement, and reseet"
class interface
COUNTER
feature -- Access
item: INTEGER --Counter's value
feature -- Element change
increment is
-- Increase counter by one
ensure
count_increased: item = old item + 1
decrement is
-- Decrease counter by one.
require
count_not_zero: item > 0
ensure
count_decreased: item = old item - 1
reset is
-- Reset counter to zero.
ensure
counter_is_zero: item = 0
invariant
positive_count: item >= 0
end

Даже если вы не знакомы с программированием на Eiffel, просто взглянув на инварианты, вы легко поймете, что делает этот класс и как именно его использовать, — прекрасное свойство автоматической документации программного обеспечения.

Теперь сравните это с аналогичным классом Java, который предлагает те же функциональные возможности, но за исключением контракта между разработчиком и разработчиком.

/**
* A Simple Example of a counter.
*
* @author Chris Boersma
*/
public class Counter {

private Integer item;

public void Counter() {}

public void create() {

item = new Integer(0);
}

public void increment() {

item++;
}

public void decrement() {

item--;
}

public void reset() {

item= new Integer(0);
}
}

Вы можете быстро увидеть, что вы теряете представление о том, что является допустимым состоянием для этого класса, и именно вам гарантированы функциональные возможности.

Теперь поставьте себя на место инструмента статического анализа. Что здесь за ошибка? Есть ли ошибки? В действительности, вероятно, нет. Вполне возможно, что этот класс функционирует именно так, как предполагалось, возможно, разработчик хотел счетчик, который можно уменьшить до значения меньше нуля. Без сомнения, чрезвычайно трудно определить, что этот код не содержит ошибок, и это всего лишь простой счетчик. Представьте себе, что нужно определить, действительно ли сложный класс из более чем 500 строк кода не содержит ошибок.

Теперь возьмите этот 500-рядный класс и интегрируйте его с другими компонентами системы, и вы быстро поймете, насколько сложными на самом деле являются инструменты статического анализа задачи и почему JSR305 действительно очень важен.

Теперь я могу быстро вникнуть в пример, иллюстрирующий, как JSR305 сделает этот код на 100% дураком, но на самом деле я не вижу в этом смысла. Прямо сейчас JSR даже не определил, какой набор аннотаций он будет поддерживать, поэтому все, что я здесь наберу, может быстро устареть и не иметь значения.

Моя цель здесь состоит лишь в том, чтобы развить свой ум и показать вам, что инструменты статического анализа, такие как FindBugs в сочетании с JSR305, могут принести целый новый мир программирования сообществу Java. Я имею в виду, сколько из нас будет утверждать, что написание более чистого и безопасного кода действительно так плохо?

На этом этапе я мог бы углубиться в различные взгляды относительно этих новых аннотаций, но я оставлю это для другого обсуждения, поскольку этот JSR развивается в нечто более конкретное. Лично я считаю, что пока рано выбирать стороны, и я лично чувствую, что есть веские доводы относительно того, имеет ли смысл этот JSR или же он абсолютно бесполезен для сообщества Java.

Я предлагаю всем следить за этим JSR, и если вы сильно чего-то хотите, откройте обсуждение на странице групп Google в JSR http://groups.google.com/group/jsr-305/ Лучше, чтобы ваш голос был услышан и представьте некоторое содержательное обсуждение с создателями JSR, а затем сядьте на забор (или ваш блог) и назовите фол.

С http://www.kungfuice.com/