أستخدام PlantUML لتسهيل رسم مخططات هندسة البرمجيات
نشر في Sep 23, 2020 بقلم السيد مذهل.
ملاحظة هامة: هذه المقالة لا تشرح معاني وعناصر المخططات وأنما تفترض معرفة القارئ بها وبأساسيات هندسة البرمجيات.
في هذه المقالة سوف أوضح طريقة أستخدام PlantUML لرسم مخططات هندسة البرمجيات وبالأخص الـ UML1, 2 وبرنامج أو صيغة PlantUML تشمل أغلب مخططات UML والمخططات الغير مشمولة هي غالباً مشتقة من أبرز المخططات (Use case, sequence, class, deployment) فيمكن محاكاتها وإيضاً هناك صيغة أخرى مدعومة مثل:
- Wireframe graphical interface
- Archimate diagram
- Specification and Description Language (SDL)
- Ditaa diagram
- Gantt diagram
- MindMap diagram
- Work Breakdown Structure diagram
- Mathematic with AsciiMath or JLaTeXMath notation
- Entity Relationship diagram
ملاحظة: مخطط وصف قواعد البيانات أو Entity Relationship diagram (ERM) يتسخدم طريقة غير طريقة تشن chen المشهورة فهذا الشيء الوحيد الذي ينقصني في PlantUML
ما هو بلانت يو أم إيل PlantUML
لا يمكن القول بأنه برنامج تعديل ورسم مخططات رسومي فطريقة PlantUML تعتمد على أن تكتب وصف مخطط بملف نصي ومن ثمة تحوله إلى رسم (صورة, صيغة متجهات, pdf, إلخ) وقد يبدو هذا غريباً للوهلة الإولى ولكن أذكر نحن كمبرمجين أو مهندسين برمجيات أو طلاب حالياً لا يمكن أن نمضى قدر جيد من الوقت ضمن مجالنا دون أن نتعلم كتابة صفحات الأنترنت والويب بأستعمال HTML, CSS, javascript فلا داعي للأستغراب أو التشكيك بفعالية الطريقة بالإخص لإي أكاديمي يستخدم لاتخ (LaTeX) لإعداد أوراقه العلمية.
وإيضاً يمكن القول بأن PlantUML لغة برمجيات خاصة لمجالها (Domain Specific Language - DSL) أو صيغة وصفية أو ما شاكل ذلك ولذا أود أن أشير إلى البدائل الرسومية:
- برنامج ArgoUML (وهو برنامج نمذجة - Modeling - وليس رسم لأنه يستطيع تحويل الرسم لشفرة مصدرية والتجوال وأستعراض النماذج على عكس PlantUML).
- برنامج Libre Office Draw (وهو برنامج رسم مخططات عام).
- برنامج Dia (وهو برنامج رسم بواجهة رسومية).
- لمزيد من البرامج يرجى الإطلاع على هذه القائمة المطولة من ويكيبيديا.
لماذا PlantUML
رسم المخططات بشكل يدوي أو ببرنامج رسومي يتطلب منك ترتيب العناصر بشكل يدوي فإذا أردت نقل عنصر وليكن مثلاً صنف (class) في مخطط مزدحم فهذا قد يتطلب منك ترتيب بقية العناصر بنفسك وبناء المخطط ببرنامج رسومي أصلاً يتطلب من معرفة الواجهة وأختصارات البرنامج ولا تملك أغلب البرامج تصميم جيد وإيضاً تضطر إلى سحب وجر العناصر وهذه عملية مملة.
ما يقدمه PlantUML هو الحل ولكن وجب التنويه بأن الخوارزمية التي ترتب العناصر ليست ذكيةً جداً فقد تحتاج لبعض التعديلات حتى تحصل على النتيجة المطلوبة.
التثبيت
بأن هذا البرامج هو برنامج مكتوب بلغة الجافا فبلإمكان تشغيله على إي جهاز يشغل Java Virtual Machine وروابط التثبيت ظاهرة على الموقع الرسمي ولا حاجة لتثبيت إي برنامج أخر يكفي إي محرر نصوص بسيط ولكن حتى نحصل التلوين والتدقيق اللغوي يمكننا تثبيت إضافات مساعدة مثل إضافة plantuml-mode لبرنامج إيماكس وكل برنامج أخر لديه إضافة مشابهة.
بالإضافة لما سبق يمكن الأستغناء عن تثبيت البرنامج وأستعمال الخدمة عبر المتصفح دون تثبيت.
2020/11/05 تحديث: بأعتبار عدم أستخدامي لنظام ويندوز أو ماك لاحظت بعد تجربة أن البرنامج يتتطلب تثبيت Graphviz معه وهو غالباً يأتي بالتوزيعات الجناوية لأنه متتطلب لبرنامج جيمب الشهير وكذلك العديد من البرامج مع العلم عند تثبيته بوندوز يجب تفعيل خيار المتغير PATH$ للجميع عند التثبيت وبعدها يمكنك تشغيل PlantUML عبر الضغط على ملف jar.
الأساسيات
ملاحظة: الأمثلة ستكون باللغة العربية للتوضيح فقط لأنه بأرض الواقع دوماً يتم أستخدام اللغة الأنجليزية
أسهل مثال هو لرسم مخطط وصف سلسلة الأحداث التي تحدث بعمليات البرنامج أو ما يسمى sequence diagram وهو أكثرها ترتيباً
@startuml ' علامتين startuml@ و enduml@ ضروريتين لكل مخطط UML ' نعم علامة ' تبدأ تعليق لسطر واحد مستخدم -> متجر /' إيضاح طريقة أستخدام تعليقات الأسطر المتعددة '/ @enduml
بعد أن تحفظ هذا المثال في ملف نصي بصيغة puml. تشغل هذا الأمر في سطر الأوامر حتى نحول الملف إلى صورة:
plantuml eg1.puml
أو يمكنك تشغيل PlantUML بدون إي خيارات فيعمل بالواجهة الرسومية ويحول كل ملف puml. إلى صورة ويسمح لك إيضاً بتغيير المجلد الحالي:
plantuml
شكل 2: صورة متحركة - كيفية أستخدام الواجهة الرسومية
كما يمكنك تحويل المخططات لصيغة غير الـ png مثل svg:
plantuml -tsvg
أو teps-
-tpdf
-ttext-
… إلخ.
لمعرفة بقية الخيارات يمكنك الإطلاع على خيار المساعدة:
plantuml -h
ولكن ربما هذا المخطط غير مألوف نوعاً ما فهناك صندوقان من الأعلى والأسفل وليس واحد فقط بالأعلى لذلك يمكننا تغيير أعدادات PlantUML الإفتراضية ونكمل التعرف على صيغته بهذا المثال:
@startuml ' هذا لإزالة الصندوق السفلي hide footbox /' كما رأينا بالمثال السابق يمكننا أستخدام المتغيرات بدون تعريفها للوهلة الأولى ولكن بتعريفها يمكننا إضفاء بعض الخصائص عليها '/ actor مستخدم مستخدم -> متجر ' من بعد ربط طرفين الأستدعاء يمكن أستخدام شارة : لوضع إي تعليق ' على المسار الممتد بين العنصرين متجر -> مخزن : أسحب (سلعة, عدد) @enduml
ومن هنا يسعنا الأنتقال لنوع أخر من مخططات UML مع العلم أن لا حاجة لتحديد نوع المخطط لأن PlantUML يتعرف تلقائياً على نوع المخطط من العناصر التي تستخدمها وإيضاً هنالك خصائص مشتركة بين المخططات مثل صناديق التعليقات (comment boxes) وبعض أنواع الأسهم التي تشترك بعض المخططات فيها ولكن أحياناً بعض الخصائص في مخطط لا توجد بأخر فلا يمكن أستخدام صنف (Class) في مخطط حالات الأستخدام (Use Case diagram).
لنأخذ مثالاً بسيطً على مخطط حالات الأستخدام:
@startuml ' غير أتجاه ترتيب العناصر في المخطط left to right direction /' ' بهذه الطريقة يمكننا وضع أسم طويل ' وبه مسافات على المتغير وفي حالتنا هو الممثل '/ actor "مشتري" as user actor "مدير" as admin ' هنا سيتم حصر حالات الأستخدام داخل نطاق النظام package متجر { ' وهكذا يتم تعريف الحالات usecase "أطلب" as uc1 usecase "إدفع" as uc2 usecase "أضف سلعة" as uc3 } ' هنا سوف نباشر العمل على الروابط user --- uc1 ' علاقة ضمنية uc1 .> uc2 : <<Inlcude>> ' أنتبه للترتيب وعدد رموز - المضافة ' هذا سيجعل الممثل يذهب لليسار ويجعل طول المسار أطول uc3 ------ admin ' هذا أحد أشكال تعريف صندوق تعليق والأتجاه محدد ' هناك عدة أشكال لتعريف صندوق التعليقات وهذا ذو الأسطر المتعددة note top of admin المقصود بالمدير هو مدير الموقع وليس مدير المتجر بحد ذاته end note @enduml
مثال على مخطط الأصناف (Class diagram):
@startuml class animal as "حيوان" { + +الأطراف : int + +الدم : string + +العمر : int } class gnu as "نو" { + +حوافر : int } class grass as "عشب" { + +سعرات : double + +تناول (int) : void } ' علاقة وراثة gnu -u-|> animal ' u == up gnu "1"-r-"0..*" grass : " يتناول " ' r == right @enduml
بالمثال السابق كان بالإمكان ترك أمر للترتيب التلقائي ولكن قمت بأدخال بعض الترتيبات
للمزيد من الأمثلة يرجى يرجى قراءة الشروحات الرسمية فهي نقطة أنطلاق جيدة ويمكن رؤية رابط لكل مخطط على الصفحة الرئيسية ولمعرفة كل الخيارات يمكن النظر بالدليل الرسمي.
قوالب جاهزة
مخطط التركيب (Deployment diagram) ذو المراحل الثلاث (Three-Tier):
@startuml skinparam componentStyle uml1 node عميل #99c1f1 { [نقال] [متصفح] } node خادم #99c1f1 { [نمط] -d- [متحكم] [عرض] -u- [متحكم] } node "قاعدة بيانات" #99c1f1 { Database "\nقاعدة البيانات\n\n" as db } [متصفح] -- [عرض] : <<HTTP/S>> [نقال] -- [متحكم] : <<HTTP/S>> [نمط] -- db : <<JDB>> @enduml
المعمارية المرجعية لتطبيقات الهاتف النقال (Mobile Application Reference Architecture):
@startuml skinparam rectangleShadowing false skinparam rectangleBorderStyle dashed skinparam componentStyle uml1 node " عميل " as Client #99c1f1 { component " متصفح " as browser } node "خادم" as Server #99c1f1 { together { rectangle "(من طبقة العرض)" as one{ [الواجهة الرسومية] - [عمليات الواجهة الرسومية] } rectangle "(من طبقة العمليات)" as BL { [واجهة التطبيق] -d- [خوارزميات\nالمعالجة] [واجهة التطبيق] -d- [عناصر\nالعملية] [واجهة التطبيق] -d- [مسار\nالعمليات] } rectangle "(من طبقة البيانات)" as DL { [الوصول\nلقواعد البيانات] - [الأدوات\nالمساعدة] [الأدوات\nالمساعدة] - [عامل\nالخدمات] } } ' together { rectangle "القطاع المشترك" as two { [الأمان] -d- [إدارة العمليات] [إدارة العمليات] -d- [التواصل] } ' } } node " " as db #99c1f1 { Database "\nمستودع بيانات\n" } node "أنظمة خارجية\nكنظام الخدمات البنكية\nوالدفع" as ext #99c1f1 browser -d- [الواجهة الرسومية] [عمليات الواجهة الرسومية] -d- [واجهة التطبيق] [الأدوات\nالمساعدة] -up- [عناصر\nالعملية] [الأدوات\nالمساعدة] -up- [خوارزميات\nالمعالجة] [الأدوات\nالمساعدة] -up- [مسار\nالعمليات] [عامل\nالخدمات] -d- ext [الوصول\nلقواعد البيانات] -d- db one -[hidden]- two @enduml
مخطط الوحدات (Modules diagram):
@startuml skinparam rectangleShadowing false skinparam rectangleBorderStyle dashed skinparam componentStyle uml1 together { rectangle "جانب العميل" as cs { package "العرض" as pcs { package "واجهة عرض المتجر" package "واجهة عرض الإدارة" package "واجهة متابعة الطلابات" } } rectangle "جانب الخادم" as ss { package "وحدة المعالجة" as bss { package "متحكم المتجر" package "متحكم الإدارة" package "متحكم الطلابات" } package "البيانات" as dss { package "نمط السلع" package "نمط المستخدمين" package "نمط الطلابات" } } bss <.u.. pcs dss <.u.. bss } @enduml
مثال موسع لمخطط وصف سلسلة الأحداث (Sequence diagram):
@startuml hide footbox ' Model entity ' View boundary ' Controller control actor "المستخدم" as user actor "نظام خارجي" as ext boundary متجر as ov <<عرض>> control متجر as oc <<متحكم>> entity متجر as om <<نمط>> hnote over ext مجرد تعليق وضع هنا دون إي هدف يذكر end note oc -> om : سجل الطلب oc -> ov : إشارة note over ov تعليق من نوع أخر وضع في عمود واجهة عرض صنف المتجر فقط هكذا end note user -> oc : تأكيد () oc -> ext : إشارة مجدداً ext -> ext : كعك user -> ov : إنهاء الطلب ov -> oc : إغلاق ($رقم) @enduml
نصيحة إضافية
عند رسم أو نمذجة مخطط حالات الأستخدام (Use case diagram) فسوف يقوم تلقائياً بوضع الحالات أو العناصر بشكل عمودي واحدة تلو الأخرى لذلك يمكن وضعهم تحت مجاميع ورصهم أفقياً بهذه الحيلة:
@startuml left to right direction actor "تاجر" as boc actor "إدارة الموقع" as admin actor "نظام خارجي" as ext actor "مستخدم" as con package نظام { together { usecase "UC-1: شيءٌ ما" as uc1 usecase "UC-2: شيءٌ ما" as uc2 usecase "UC-3: شيءٌ ما" as uc3 usecase "UC-4: شيءٌ ما" as uc4 usecase "UC-12: شيءٌ ما" as uc12 usecase "UC-5: شيءٌ ما" as uc5 usecase "UC-10: شيءٌ ما" as uc10 } together { usecase "UC-7: شيءٌ ما" as uc7 usecase "UC-8: شيءٌ ما" as uc8 usecase "UC-9: شيءٌ ما" as uc9 usecase "UC-6: شيءٌ ما" as uc6 usecase "UC-13: شيءٌ ما" as uc13 usecase "UC-11: شيءٌ ما" as uc11 } } uc1 -[hidden]- uc7 boc -- uc1 boc -- uc2 boc -- uc3 boc -- uc4 boc -- uc5 boc -- uc10 boc -- uc11 boc -- uc13 admin -- uc7 admin -|> boc uc6 -- ext uc8 -- con uc9 -- con uc4 <. uc12 : <<extends>> @enduml
وكما يمكنك إيضاً تضمين المخطط داخل الشفرة المصدرية ضمن تعليق و PlantUML سوف يتعرف عليه لأن يبدأ ب @startuml
وينتهي بــ @enduml
من ما يتيح لك أستخدامه مع مولدات الوثائق (Documentation generators) مثل GtkDoc و JavaDoc و Doxygen وغيرها من المولدات وهذا مثال لتضمين المخطط السابق داخل شفرة مصدرية للغة البرمجة سي (C programming language):
/* @startuml left to right direction actor "تاجر" as boc actor "إدارة الموقع" as admin actor "نظام خارجي" as ext actor "مستخدم" as con package نظام { together { usecase "UC-1: شيءٌ ما" as uc1 usecase "UC-2: شيءٌ ما" as uc2 usecase "UC-3: شيءٌ ما" as uc3 usecase "UC-4: شيءٌ ما" as uc4 usecase "UC-12: شيءٌ ما" as uc12 usecase "UC-5: شيءٌ ما" as uc5 usecase "UC-10: شيءٌ ما" as uc10 } together { usecase "UC-7: شيءٌ ما" as uc7 usecase "UC-8: شيءٌ ما" as uc8 usecase "UC-9: شيءٌ ما" as uc9 usecase "UC-6: شيءٌ ما" as uc6 usecase "UC-13: شيءٌ ما" as uc13 usecase "UC-11: شيءٌ ما" as uc11 } } uc1 -[hidden]- uc7 boc -- uc1 boc -- uc2 boc -- uc3 boc -- uc4 boc -- uc5 boc -- uc10 boc -- uc11 boc -- uc13 admin -- uc7 admin -|> boc uc6 -- ext uc8 -- con uc9 -- con uc4 <. uc12 : <<extends>> @enduml */ #include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { printf("Happy, Hacking\n"); return 0; }