2014-02-23

О PlantUML

Все любят диаграммы. Все архитекторы/менеджеры/начальники рисуют диаграммы. Стандартными диаграммами являются диаграммы на UML.

Чтобы рисовать диаграммы (как UML, так и другие) существует множество инструментов: MS Visio, DiayEd. Даже LibreOffice/OpenOffice.org Draw или Google Drive Drawing могут быть полезны. Ну а под Андроид есть великолепный DrawExpress Diagram, где диаграммы можно рисовать прямо пальцем.

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


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

Графы — это хорошо. Но нам нужны диаграммы. Поэтому существует PlantUML (технически — это надстройка над Graphviz). Эта штука позволяет описывать UML диаграммы текстом (на своем языке для разных типов диаграмм) и генерировать картинки. Это не единственный инструмент подобного рода, но самый популярный и функциональный. PlantUML встраивается в вики-движки (включая Confluence и MediaWiki), в IDE и текстовые редакторы (включая Eclipse и IDEA). Но самый простой способ попробовать PlantUML действии — запустить сервлет у себя или же воспользоваться уже работающим сервером plantuml.com.


Чем хорошо описывать диаграммы текстом? Писать получается быстрее, чем рисовать. Не нужно заботиться (до определенного момента) о расположении блоков и связей на диаграмме, инструмент визуализации сделает все сам. Легко модифицировать диаграмму: добавление новых блоков и связей не является проблемой. Текстовое представление диаграммы вполне читабельно. Текст легко версионируется, и (как минимум, в Confluence) вам доступна и видна вся история изменений диаграммы (что довольно тяжело отследить в случае хранения изображений). Диаграммы получаются одинаково аккуратными, независимо от вашего умения распологать прямоугольники на плоскости. Есть один побочный эффект, вытекающий из ограничений алгоритмов визуализации, — если ваша диаграмма слишком сложна (содержит слишком много блоков и связей), то она автоматически превратится в нечитаемое месиво, что означает, что вам нужно разбить эту диаграмму на две или более. Это хорошо, потому что большие диаграммы, даже если они выглядят понятными, на самом деле очень плохо воспринимаются и не запоминаются.

Есть и недостатки. Ваш контроль над внешним видом диаграммы очень ограничен. И практика работы с PlantUML показывает, что чем меньше вы этими средствами контроля пользуетесь, тем лучше получается диаграмма. Также вы не можете точно предсказать, как диаграмма будет выглядеть. Почти невозможно выделить какие-то элементы, расположив их в определенном месте диаграммы (в левом верхнем углу, например), все равно все может уехать. Используйте выделение цветом.

Диаграмма последовательностей. Самая простая диаграмма. Используйте её, если нужно показать порядок взаимодействия компонент. Я предпочитаю сначала перечислить все компоненты, задав тем самым порядок их расположения на диаграмме, а потом рисовать сообщения. Мне больше нравится явно писать слова actor, participantdatabase, чем полагаться на нотации типа :actor:.

 actor Twilight  
 boundary Spike  
 actor Celestia  
   
 Twilight -> Spike : letter  
 activate Spike  
 Spike -> Spike : fire-breath  
 Spike --> Celestia : letter  
 deactivate Spike  
 activate Celestia  
 ...  
 Celestia --> Spike : answer  
 deactivate Celestia  
 activate Spike  
 Spike -> Spike : belch  
 Spike -> Twilight : answer  
 deactivate Spike  

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

Диаграмма классов. Очень полезная диаграмма. Можно описать классы, методы, свойства, связи, включая наследование и композицию, с указанием ролей в связи. Можно объединять классы в пакеты. Чаще я описываю не классы языка программирования, а классы предметной области: что куда входит и как друг с другом соотносится. А еще чаще использую для описания структуры БД. Обычно сначала я описываю классы и их вхождение в пакеты, а потом расставляю связи.

 package MLP <<cloud>> {  
   
  class Pony {  
   head  
   body  
   legs  
   tail  
  }  
   
  class Unicorn {  
   corn  
  }  
   
  class Pegasus {  
   wings  
  }  
   
  class Alicorn  
   
 }  
   
 Pony <|-- Unicorn  
 Pony <|-- Pegasus  
 Unicorn <|-- Alicorn  
 Pegasus <|-- Alicorn  
   
 Pony ..> Pony : friend of >  

Диаграмма деятельности. По сути — блок-схема. В PlantUML есть два варианта синтаксиса для этих диаграмм. Первый подразумевает явное описание всех стрелочек-переходов. Второй (еще в бете) больше похож на язык программирования, со всякими if-else-endif. Я не люблю эту диаграмму, потому что даже псевдокод исходника диаграммы для меня понятнее, чем блок-схема. Хотя некоторые разработчики находят диаграмму деятельности полезной и понятной.

Диаграмма компонент. Моя любимая диаграмма. Тут можно разрисовать и логическую структуру системы: кто с кем по каким протоколам взаимодействует. И физическую структуру того, как оно все развернуто: на каком узле какие процессы запущены и в каких датацентрах сами узлы находятся. Компоненты прекрасно объединяются в узлы (блок node) и облака (cloud).

 cloud Equestria {  
  frame Canterlot {  
   actor Celestia  
  }  
  frame Ponyville {  
   actor Twilight  
  }  
  frame "Everfree Forest" {  
   actor Zecora  
  }  
 }  
 cloud "Crystal Empire" {  
  actor Cadance  
 }  
   
 Celestia - Twilight  
 Twilight - Zecora  
   
 Celestia - Cadance  
 Twilight - Cadance  

Диаграмма состояний. Полезна не только в тех случаях, когда у вас в коде присутствует конечный автомат. Но и тогда, когда вам нужно высокоуровнево описать состояния системы, её частей или структуры данных.

 state "Twilight Sparkle" as Twily  
 Twily : unicorn, Princess Celestia's student  
   
 state "Princess Twilight Sparkle" as Princess  
 Princess : alicorn, princess of Equestria  
   
 [*] --> Twily  
 Twily --> Princess : solve Star Swirl's spell  

Порядок блоков на этой и других подобных диаграммах определяется не столько порядком их объявления, сколько порядком объявления связей. Однако блоки, объединенные в пакет, отображаются вместе, так что полезно добавлять пакеты, если блоки начинают расползаться по диаграмме хаотично. "Одинарная" связь (с одним минусиком) как правило располагает блоки слева направо в одну строку. Если таким образом связаны более двух блоков, то рисуются длинные дуги. "Двойная" связь (с двумя минусиками) выстраивает блоки сверху вниз. Это связь из одного ряда блоков к следующему. Большее число минусиков нужны для более длинных связей: через ряд или более блоков.

Хоть PlantUML и позволяет задавать направления связей и влиять таким образом на порядок расположения блоков, лучше этими возможностями не пользоваться. Это усложняет последующую модификацию диаграммы (вы возвращаетесь к проблеме правильного ручного расположения блоков). Да и результат не всегда предсказуем, диаграмме может сделаться хуже. Регулируйте расположение блоков порядком их объявления, как в рамках одной связи (помните, всегда слева направо или сверху вниз), так и порядком объявления самих связей.

Помните, что почти на каждой диаграмме блоку можно назначить псевдоним (ключевое слово as). Это позволяет давать блокам длинные многословные имена, а ссылаться на короткие имена. Также это единственный способ ввести на диаграмму несколько блоков с одинаковыми подписями.

Я так часто пользуюсь PlantUML, что даже набросал маленькое приложеньице для Андроид, которое перегоняет текст в изображение через PlantUML сервер.