Sơ đồ mạng dưới dạng mã/Sơ đồ mạng dưới dạng mã

Trong vài năm gần đây, tôi đã tham gia nhiều hơn vào công việc tài liệu. Viết một văn bản giải thích về cách hoạt động của một hệ thống cụ thể nói chung khá đơn giản. Việc vẽ sơ đồ sẽ hiển thị tất cả các đối tượng chính và mối liên hệ giữa các đối tượng này cũng khá dễ dàng.

Nhưng khía cạnh có vấn đề nhất là việc cập nhật tài liệu này. Và văn bản thì ổn, nhưng sơ đồ... Bởi vì... tất cả tài liệu đều trực tuyến, tức là ở định dạng html thì văn bản sẽ đi kèm với hình ảnh gif/jpeg/png, những hình ảnh này thực sự hiển thị sơ đồ. Và sơ đồ được vẽ trong nhiều chương trình khác nhau như Visio hoặc các dịch vụ trực tuyến a la draw.io. Sau đó, bạn xuất sơ đồ sang định dạng đồ họa và đính kèm vào html. Nó đơn giản.

Vấn đề là gì?

Các kế hoạch thường đơn giản. Chính xác hơn, không phức tạp lắm. Có, số lượng đối tượng là một hoặc hai đối tượng, số lượng kết nối gần như nhau. Cộng với chữ ký, một số chỉ định. Những kế hoạch đơn giản có thể được mô tả bằng lời, nhưng những kế hoạch quá phức tạp, ahem... (c) “họ sẽ không hiểu, thưa ngài.” Có rất nhiều kế hoạch, những thay đổi cần phải được thực hiện theo định kỳ, theo từng giai đoạn, tức là. liên tục, bởi vì họ theo dõi sự phát triển của sản phẩm của chúng tôi.

Bạn có thể nhúng html của dịch vụ. Bạn đã thử chưa?

Vâng, chắc chắn rồi. Ví dụ: tôi thích đồ họa từ gliffy.com. Nhưng để thực hiện thay đổi, bạn cần truy cập dịch vụ của bên thứ ba và chỉnh sửa ở đó. Và việc giao việc sửa chữa cho đồng nghiệp sẽ khó khăn hơn.

Phải làm gì?

Gần đây tôi tình cờ thấy một kho lưu trữ trên Github trong phần khuyến nghị github.com/RaoulMeyer/diagram-as-code. Sơ đồ dưới dạng mã. Những thứ kia. chúng tôi mô tả mạch chúng tôi cần trong js. Chúng tôi viết js này trực tiếp trong cùng một html chứa văn bản tài liệu khác.

Nhân tiện, tôi viết tài liệu không hoàn toàn bằng html. Thông thường, tài liệu là một tập hợp các tệp có văn bản đánh dấu, sau đó được một số công cụ chuyển đổi thành một trang tài liệu chính thức, chẳng hạn như Wintersmith. Hoặc một hệ thống wiki.

Hóa ra rất thuận tiện: chúng tôi đã viết văn bản, sau đó thẻ script sẽ mở ra và mã JS của lược đồ được mô tả trong đó.

Lại có chuyện gì vậy?

Tôi thích kho lưu trữ này, nhưng đây không phải là ví dụ duy nhất trong đó sơ đồ được vẽ bằng cách sử dụng mã hoặc biểu diễn văn bản. (Cuối bài viết sẽ có link các dự án, bài viết mà mình Google trên sơ đồ chủ đề dưới dạng code.)

Và tôi không phải là người duy nhất chỉnh sửa tài liệu. Đôi khi đồng nghiệp cũng đóng góp - sửa một từ, thay đổi mô tả, chèn hình ảnh mới. 

Vì vậy, tôi muốn xem sơ đồ ở định dạng văn bản dễ đọc, dễ hiểu mà không cần phải mất nhiều thời gian học tập. Và ở một số nơi, bạn thậm chí có thể chỉ cần sao chép-dán để tăng tốc độ thêm mạch mới. 

Và một đồng nghiệp khác lưu ý rằng mã tất nhiên là tốt, nhưng nếu bạn sử dụng cấu trúc, mọi thứ có thể rất nghiêm ngặt và mang tính biểu cảm.

Vì vậy, tôi đã cố gắng tưởng tượng sơ đồ như một tập hợp nhiều mảng nhỏ mô tả các nút, kết nối, nhóm nút cũng như vị trí của các nút. Theo quan điểm khiêm tốn của tôi, nó hóa ra khá tiện lợi, mặc dù tất nhiên, hương vị và màu sắc...

Làm thế nào đây là một biểu đồ trong một mảng?

  • Mỗi nút được mô tả bằng một mã định danh xác định duy nhất nút đó.
  • Bạn cũng có thể thêm biểu tượng vào nút và thêm dòng chữ.
  • Bạn có thể chỉ định mối quan hệ giữa hai nút.
  • Để giao tiếp trên sơ đồ, bạn có thể đặt màu sắc và dòng chữ.
  • Hướng truyền thông được xác định là từ nguồn tới đích. Và nguồn và đích được chỉ định bởi các mã định danh nút.
  • Một hoặc nhiều nút có thể được thêm vào một nhóm.
  • Mối quan hệ cũng có thể được chỉ định cả từ nhóm và nhóm.

Sử dụng các quy tắc đơn giản này, chúng ta có được sơ đồ sau. Chỉ? Khá.

Sơ đồ mạng dưới dạng mã/Sơ đồ mạng dưới dạng mã

Và nó được mô tả bằng mã js sau. Điều chính ở đây là đối tượng phần tử. Trong đó các nút được chỉ định - nút, cạnh - kết nối.
 

  const elements = {
    nodes: [       // описываем узлы
      { id: 'client', type: 'smartphone', label: 'Mobile App'},
      { id: 'server', type: 'server', label: 'Main Server'},
      { id: 'db1', type: 'database', label: 'DB 1'},
      { id: 'db2', type: 'database', label: 'DB 2'},
    ],
    edges: [       // указываем связи
      { source: 'client', target: 'server', label: 'request' },
      { source: 'server', target: 'db1', label: 'request' },
      { source: 'server', target: 'db2', label: 'request' },
    ],
  };
  Diagram('scheme1', elements);

Tất nhiên, tôi không tự mình nghĩ ra bản vẽ mạch điện mà sử dụng thư viện cytoscape.js là một công cụ trực quan rất mạnh mẽ. Tôi chỉ sử dụng một phần khả năng trong giải pháp của mình. 

Được rồi, đây là một ví dụ đơn giản. Nó có thể phức tạp hơn?

Vâng, làm ơn. Để biểu thị vị trí, chúng tôi sử dụng vị trí, để biểu thị các nhóm, chúng tôi chỉ ra danh sách các nhóm trong nhóm và bản thân các phần tử có thuộc tính nhóm.

Sơ đồ mạng dưới dạng mã/Sơ đồ mạng dưới dạng mã

Và đây là mã:

<div id="scheme5" style="height:500px;width:800px;"></div>
<script>
  const elements5 = {
    groups: [
      { id: 'g1', label: 'Группа сервисов 1'},
      { id: 'g2', label: 'Группа сервисов 2'},
    ],
    nodes: [
      { id: 'man1', type: 'person', label: 'Человек'},
      { id: 'client', type: 'smartphone', label: 'Смартфон'},
      { id: 'agent-backend', type: 'server', group: 'g1', label: 'agent-backend'},
      { id: 'web', type: 'server', group: 'g1', label: 'Приложение admin'},
      { id: 'www', type: 'server', group: 'g1', label: 'страница загрузки'},
      { id: 'mongodb1', type: 'database', group: 'g1', label: 'Mongo DB 1'},
      { id: 'mongodb2', type: 'database', group: 'g1', label: 'Mongo DB 2'},
      { id: 'runner-integration1', type: 'worker', group: 'g1', label: 'отправка'},
      { id: 'runner-integration2', type: 'worker', group: 'g1', label: 'отправка'},
      { id: 'api', type: 'server', group: 'g1', label: 'API'},
      { id: 'server2', type: 'server', group:'g2', label: 'сервер'},
      { id: 'otherServer', type: 'server', group:'g2', label: 'сервер'},
      { id: 'firebase', type: 'cloud', label: 'Google Firebase'},
    ],
    edges: [
      { source: 'client', target: 'agent-backend', label: 'json', color: 'red' },
      { source: 'agent-backend', target: 'mongodb1', color: 'red' },
      { source: 'agent-backend', target: 'mongodb2',  color: 'red' },
      { source: 'mongodb1', target: 'runner-integration1', label: 'данные' },
      { source: 'mongodb2', target: 'runner-integration2', label: 'данные' },
      { source: 'mongodb1', target: 'web', label: 'данные для отображения' },
      { source: 'runner-integration1', target: 'server2', label: 'данные' },
      { source: 'runner-integration2', target: 'otherServer', label: 'данные' },
      { source: 'api', target: 'firebase', label: 'запросы', color: 'blue', },
      { source: 'firebase', target: 'client', label: 'push', color: 'blue'},
      { source: 'server2', target: 'api', label: 'уведомления', color: 'blue'},
      { source: 'man1', target: 'client', },
    ],
    positions: [
      { id: 'client', row: 2, col: 1,},
      { id: 'agent-backend', row: 2, col: 3,},
      { id: 'web', row: 6, col: 3,},
      { id: 'www', row: 1, col: 3,},
      { id: 'mongodb1', row: 1, col: 4,},
      { id: 'mongodb2', row: 2, col: 5,},
      { id: 'runner-integration1', row: 3, col: 3,},
      { id: 'runner-integration2', row: 4, col: 3,},
      { id: 'api', row: 5, col: 3,},
      { id: 'server2', row: 6, col: 7,},
      { id: 'otherServer', row: 4, col: 7,},
      { id: 'firebase', row: 5, col: 1,},
      { id: 'logger', row: 2, col: 7,},
      { id: 'crm', row: 5, col: 8,},
    ],
};
  Diagram('scheme5', elements5, {layout: 'grid'});
</script>

Một mặt, sơ đồ như vậy gần như là một vài màn hình mã trên máy tính xách tay, mặt khác, cấu trúc a la json cho phép bạn điền tất cả dữ liệu bằng cách tương tự một cách nhanh chóng và bạn có thể sao chép-dán.

Tại sao các vị trí được đặt riêng biệt với các nút?

Nó thoải mái hơn. Đầu tiên chúng ta chỉ định các nút. Sau đó chúng ta có thể chỉ định một vài nhóm và chỉ ra chúng trong các nút. Sau đó, chúng tôi chỉ định các kết nối. Và chỉ khi đó, khi có các đối tượng chính và mối liên hệ giữa chúng, chúng ta mới đảm nhận vị trí của các đối tượng này trên sơ đồ. Hoặc ngược lại.

Có thể không có vị trí?

Có thể không có vị trí. Nhưng nó sẽ hơi nhàu nát; bạn có thể thấy tùy chọn này trong các ví dụ. Điều này là do thực tế là có một thuật toán xác định vị trí các nút cho cytoscape fcose, điều này cũng tính đến sự hiện diện của các nhóm. Việc chỉ định các vị trí làm cho sơ đồ dễ kiểm soát hơn, nhưng ở giai đoạn phác thảo sơ đồ đầu tiên, có thể không có vị trí.

Vị trí cũng có thể được chỉ định theo kiểu Chiến hạm. Những thứ kia. một nút nằm ở a1 và nút kia ở d5. Nó đặc biệt giúp cho cytoscape làm cho các đối tượng trên khung vẽ có thể di chuyển được, tức là. chúng ta có thể di chuyển chúng xung quanh, xem các tùy chọn bố cục khác nhau và sau đó sửa cách sắp xếp các thành phần mà chúng ta thích trong mã.

Nói chung là có thể hiểu được. Bạn cũng có thể thử?
 
Tất nhiên, để nhanh chóng tạo ra các mạch điện, tôi đã tự làm cho mình một cái người biên tập, chính nó cập nhật lược đồ và lưu trữ phiên bản mới nhất trong trình duyệt (trong localStorage).

Bạn đã thử chưa? Bây giờ bạn có thể thêm nó vào trang của bạn.

Sau đó một lần nữa:

1. Kết nối kịch bản

<script src="https://unpkg.com/@antirek/[email protected]/dist/code-full.min.js"></script>

2. Thêm mã vào html

<div id="scheme1" style="height:300px;width:800px;"></div>
<script>      
  const elements = {    
    nodes: [
      { id: 'client', type: 'smartphone', label: 'Mobile App'},
      { id: 'server', type: 'server', label: 'Main Server'},
      { id: 'db1', type: 'database', label: 'DB 1'},
      { id: 'db2', type: 'database', label: 'DB 2'},
    ],
    edges: [
      { source: 'client', target: 'server', label: 'request' },
      { source: 'server', target: 'db1', label: 'request' },
      { source: 'server', target: 'db2', label: 'request' },
    ],
  };
  Diagram('scheme1', elements);
</script>

3. chúng tôi chỉnh sửa mã theo sơ đồ chúng tôi cần (tôi nghĩ nó dễ hơn vẽ một con cú :)

Thêm chi tiết tại trang dự án trên github.

Kết quả ra sao?

Tôi đã đạt được mục tiêu của mình - thêm sơ đồ nội tuyến vào tài liệu, định dạng khá đơn giản và dễ hiểu. Nó không phù hợp với các siêu mạch, nhưng đối với các mạch nhỏ giải thích cấu trúc của các kết nối thì hoàn toàn ổn. Bạn luôn có thể nhanh chóng điều chỉnh và thay đổi điều gì đó theo thời gian. Có, và đồng nghiệp có thể tự sửa nội dung nào đó trong dock, ít nhất là chú thích cho đồ vật mà không cần đào tạo đặc biệt))

Những gì có thể được cải thiện?

Tất nhiên, có rất nhiều lựa chọn ở đây. Thêm các biểu tượng bổ sung (tất cả các biểu tượng hiện có đều được thêm vào dòng lệnh). Chọn một bộ biểu tượng biểu cảm hơn. Làm cho nó có thể chỉ định kiểu của đường kết nối. Thêm hình nền.

Bạn nghĩ sao?
 
Tôi đã có một số ý tưởng để triển khai các vấn đề, bạn cũng có thể thêm ý tưởng của mình vào phần nhận xét.

Giải pháp của tôi chắc chắn có thể áp dụng được trong một phạm vi hẹp các vấn đề và có lẽ bạn sẽ tìm thấy một công cụ thuận tiện hơn để vẽ sơ đồ bằng cách mã hóa chúng - như người ta nói 'hãy cho tôi xem sơ đồ của bạn dưới dạng mã'

  1. lựa chọn tốt
  2. Dịch vụ tuyệt vời (9 loại biểu đồ biên tập trực tuyến)
  3. Tất nhiên là nàng tiên cá.js
  4. Và nếu bạn thích những sơ đồ siêu chi tiết và phức tạp thì chắc chắn bạn sẽ ngưỡng mộ dự án này: go.drawthe.net

Nguồn: www.habr.com

Thêm một lời nhận xét