Pull to refresh

Использование Graphviz для построения блок-схем

Reading time3 min
Views27K
Мы создаем ПО для разработки и поддержки баз данных Oracle, и статический анализатор PL/SQL является одной из основных фич наших приложений. Кто знаком с Oracle, тот хорошо знает что такое PL/SQL.

Известная поговорка гласит: «Лучше один раз увидеть, чем сто раз услышать». Поэтому мы решили заимпрувить статический анализатор таким образом, чтобы он визуализировал код в виде блок-схем (Flowcharts) и диаграмм вызовов (Call Trees). Хоть и нарисовать блоки и их связи несложно, оптимизировать их расположение на «листе» представлялось задачей, требующей значительных усилий. Чтобы стрелки минимально пересекались и обтекали блоки, блоки объединялись в группы, и диаграмма при этом не превращалась в «кашу», нужно было потратить много сил и времени.

И тогда мы решили поискать готовое решение, дабы не изобретать велосипед. Наше внимание сразу привлек Graphviz – open source решение по визуализации диаграмм. Первые его версии были разработаны компанией AT&T, а теперь он доступен как набор утилит и библиотек, а также в исходниках под лицензией Eclipse Public License (EPL).

Его движок диаграмм использует язык описания графов DOT, который представляет собой текстовое описание структуры графа: вершины, их связи, группы и атрибуты для их визуального оформления.

Описание простейшего графа:

digraph graphname {
  a -> b;
}

Если необходимо добавить узлам атрибуты, например подписи, то необходимо отдельно описать узлы:

digraph graphname {
  a [label="source"]
  b [label="destination"]
  a -> b;
}

Далее покажу на примере простой процедуры на PL/SQL:

CREATE PROCEDURE WRITE_STRING(
    P_MESSAGE_TYPE IN NUMBER
  , P_MESSAGE IN VARCHAR2
)
IS
BEGIN
  IF P_MESSAGE_TYPE >= LOG_LEVEL THEN
    ADD_LOG_RECORD(P_MESSAGE_TYPE, P_MESSAGE);
  END IF;
END WRITE_STRING;

Код понятен, даже если вы не знакомы с синтаксисом PL/SQL.

А теперь опишем этот код на языке DOT. Пояснения снова излишни:

digraph G {
  N0 [label="”]
  N1_COND [label="P_MESSAGE_TYPE \>= LOG_LEVEL ?"];
  N2 [label="ADD_LOG_RECORD(P_MESSAGE_TYPE, P_MESSAGE);"];
  EXIT_LABEL [label="END"];
  
  N0 -> N1_COND
  N1_COND -> N2
  N1_COND -> EXIT_LABEL
  N2 -> EXIT_LABEL 
}

Теперь можно «скормить» этот файл Graphviz, подставив соответственно вместо %PNGFILE% и %DOTFILE% имена выходного (png) и входного (dot) файлов:

dot -v -Tpng –o%PNGFILE% %DOTFILE%

При помощи Graphviz из описания выше получается такая картина:



Наглядно, но весьма аскетично.

Можно сделать диаграмму привлекательнее, добавив атрибуты для определения формы блоков (shape=diamond), подписи стрелок (label="Yes") и цвета color, fontcolor.

Также мы можем объединить в подграф блоки, которые являются исполняемыми. Это реализуется конструкцией subgraph {}, внутри которой мы можем перечислить имена блоков, включенных в подграф, и указать атрибуты для визуального оформления (цвет рамки).

digraph G {
  comment="PL/SQL flowchart generated by ClearSQL";
  node [fontname="Arial", fontsize=8, height=.2, width=.25, color="#000000", fontcolor="#000000"];
  edge [fontname="Arial", fontsize=8, arrowsize=.8, color="#000000", fontcolor="#000000"];
  
  N0 [shape=plaintext, label="", style=invis];
  N1_COND [shape=diamond, conditional=true, label="P_MESSAGE_TYPE \>= LOG_LEVEL ?"];
  N2 [shape=box, label="ADD_LOG_RECORD(P_MESSAGE_TYPE, P_MESSAGE);"];
  EXIT_LABEL [shape=Msquare, label="END"];
  
  N0 -> N1_COND [color=darkgoldenrod];
  N1_COND -> N2 [label="  Yes " color="#228b22" fontcolor="#228b22"];
  N1_COND -> EXIT_LABEL [label="  No " color="#ff7e40" fontcolor="#ff7e40"];
  N2 -> EXIT_LABEL  
  
  subgraph "cluster_#1" {
    color="#0000ff"; 
    N1_COND; N2
  }  
}

Получается вполне симпатичная блок-схема, которую и людям показать не стыдно.



Чтобы код могли читать не только программисты, но и «простые смертные», мы придумали такую фишку: приделали распознавание специальных тегов в комментариях, которые бы разработчик писал как псевдокод – язык описания алгоритмов. Это помогло увеличить ценность блок-схемы, которая теперь может отображать бизнес-логику, а не только визуализировать листинг.

CREATE PROCEDURE WRITE_STRING(
      P_MESSAGE_TYPE IN NUMBER
    , P_MESSAGE IN VARCHAR2
)
IS
BEGIN
  --## Уровень данного сообщения по отношению к порогу журналирования
  --##@true Выше
  --##@false Ниже
  IF P_MESSAGE_TYPE >= LOG_LEVEL THEN
    --## Добавляем запись в журнал
    ADD_LOG_RECORD(P_MESSAGE_TYPE, P_MESSAGE);
  END IF;
END WRITE_STRING;

Вуаля! Graphviz дает возможность делать потрясающие визуализации с минимальными затратами.


Tags:
Hubs:
+10
Comments17

Articles

Change theme settings