Draw - programming software design diagrams
This module provides an API to program software design diagrams using the Go programming language.
Drawing diagrams by hand, though very intuitive and easy to
create are rarely maintained over time. If we want to keep
them up to date with our code, we need another
way.
Autogenerated diagrams from source code is one way to
go about it. However then the problem becomes one of making it
informative enough for the inteded audience, ie. it's more
difficult to filter out unwanted elements or place them in a
logical order depending on the discussion/purpose.
We can
also resort to using text formats and process those into
diagrams, eg. mscgen or graphviz. These are great tools which
bring design diagrams closer to the source code and benefit
from the same revision control as other code. The problem of
maintaining diagrams however remains, refactoring code doesn't
touch the diagrams.
This module uses the benefits of the text base diagram formats by using the Go programming language. Ie. not another format rather it provides an API for programming diagrams. Developers can refer to types directly from the modules they want to describe. Whatever information can be gathered from the source code is used, which allows the programmer to focus on creating a diagram visually suitable for their reader.
Install
go get github.com/gregoryv/draw/...
API documentation
- draw
- draw/shape - SVG shapes
- draw/design - software design diagrams
About
Written by Gregory Vinčić
MIT License
Quick start
Each diagram is a Go type specifically designed to provide
an easy and intuitive way of "programming" diagrams. Elements
are either fixed strings or taken from the source code by
using concrete instances of real types. This allows for
refactoring to also update diagrams within a package.
Once you selected which elements to include, position them
relative to each other in the diagram. Relative placement has
the benefit of adaptive diagrams once you add more methods or
fields to your structs. It works for most cases, eliminating
manual updates.
package docs
import (
"github.com/gregoryv/draw/design"
"github.com/gregoryv/draw/shape"
)
func ExampleSmallClassDiagram() *design.ClassDiagram {
var (
d = design.NewClassDiagram()
house = d.Struct(House{})
door = d.Struct(Door{})
window = d.Struct(Window{})
part = d.Interface((*Part)(nil))
note = shape.NewNote(`Relations are automa-
tically rendered`)
)
d.Place(part).At(20, 20) // absolute positioning
d.Place(door).RightOf(part, 70) // optional extra spacing
d.Place(window).Below(door)
d.Place(house, note).RightOf(door, 70)
d.HAlignCenter(house, door, part, note)
d.SetCaption("Small example diagram")
return d
}
Once a diagram is done, you can render the SVG in different ways
SaveAs(filename)
Inline()
- returns SVG as string with all classes replaced with stylingWriteSVG(io.Writer)
These pages for instance are generated using the github.com/gregoryv/web package using the Inline() method and looks something like the below code
package docs
import . "github.com/gregoryv/web"
func Example_RenderInlinedDiagram() {
page := NewPage(
Html(
Body(
H1("An example"),
ExampleSmallClassDiagram().Inline(),
),
),
)
page.SaveAs("mypage.html")
}
Styling is currently provided by draw.ClassAttributes
and can be changed to some
degree. For now font size and family should not be changed
as size of shapes will not adapt to the styling
values. The idea is however that the default styling
should be left alone.
There are more design diagram types available, take a look below. If you are missing something that could benefit the community, please let me know.
Diagrams
Class
In class diagrams the author wants to convey design relations between various entities. However the relations and most of the element naming can be generated from the source code. The author should add what is needed for a clear picture, ie. selecting entities to show and position them in a perceptible manner.
Source: class_example.go
Records describe each entity using package name and type. Methods and fields are shown only by name if visible. Details such as arguments and return values are left to the API documentation. Relations are automatically rendererd between entities if there is one.
Activity
Activity diagrams start in one position and show states and activities transitioning from one stated to another ending in one or more exits.
package docs
import (
"github.com/gregoryv/draw/design"
)
func ExampleActivityDiagram() *design.ActivityDiagram {
d := design.NewActivityDiagram()
d.Start().At(80, 20)
d.Trans("push", "Commited")
d.Trans("run git hook", "Build complete")
test := d.Decide("run tests")
d.Trans("ok", "Verified")
d.Trans("", "EXIT")
d.Or(test)
d.TransRight("fails", "EXIT")
return d
}
Sequence
Sequence diagrams are ment to describe a sequence of events, specifically calling methods or remote API calls. I've tried to emphasize the horizontal arrows over vertical lines and keep visual effects to a minimum. For now there is only one arrow variation. I found that embedding information by the subtle head variations and arrow line styling is hard to read.
package docs
import (
"database/sql"
"github.com/gregoryv/draw/design"
"github.com/gregoryv/draw/internal/app"
)
func ExampleSequenceDiagram() *design.SequenceDiagram {
var (
d = design.NewSequenceDiagram()
cli = d.AddStruct(app.Client{})
srv = d.AddStruct(app.Server{})
db = d.AddStruct(sql.DB{})
sqs = d.Add("aws.SQS")
)
d.Group(srv, sqs, "Private RPC using Gob encoding", "red")
d.Link(cli, srv, "connect()")
d.Link(srv, db, "SELECT").Class = "highlight"
d.Link(db, srv, "Rows")
d.Link(srv, srv, "Transform to view model").Class = "highlight"
d.Link(srv, cli, "Send HTML")
d.Link(srv, sqs, "Publish event")
return d
}
C4 diagrams
package docs
import (
"github.com/gregoryv/draw/design"
"github.com/gregoryv/draw/shape"
)
func ExampleC4SystemContextDiagram() *design.Diagram {
var (
d = design.NewDiagram()
customer = shape.NewCard("Personal Banking Customer", "[Person]",
`A customer of the bank, with personal
bank accounts.`,
)
ibs = shape.NewCard("Internet Banking System", "[Software System]",
`Allows customers to view information
about their bank accounts, and make
payments.`,
)
mailsys = shape.NewCard("E-mail System", "[Software System]",
`The internal Microsoft Exchange
e-mail system.`,
)
mainframe = shape.NewCard("Mainframe Banking System", "[Software System]",
`Stores all of the core banking
information about customers,
accounts, transactions, etc.`,
)
)
mailsys.SetClass("card-external")
mainframe.SetClass("card-external")
customer.SetIcon(shape.NewActor())
d.Place(customer).At(20, 20)
d.Place(ibs).Below(customer, 170)
d.Place(mailsys).RightOf(ibs, 200)
d.Place(mainframe).Below(ibs, 170)
d.HAlignCenter(ibs, mailsys)
d.VAlignCenter(customer, ibs, mainframe)
d.Link(customer, ibs,
"Views account\nbalances, and\nmakes payments\nusing",
)
d.Link(ibs, mailsys, "Sends e-mail\nusing")
d.Link(mailsys, customer, "Sends e-mail to")
d.Link(ibs, mainframe,
"Gets account\ninformation from,\nand makes\npayments using",
)
d.SetCaption("C4 example diagram")
return d
}
Gantt chart
Generic
Shapes
Changelog
## [0.34.0-dev]
- Fix shape.Container width, wrap to grouped objects
- Add C4 example
## [0.33.0] 2023-10-21
- Use gregoryv/web v0.25.0
## [0.32.0] 2023-10-08
- Enable scaling of diagrams and shapes, e.g. Diagram.SetScale(1.5)
- Shapes no longer implement fmt.Stringer
- Hide field Note.Text
## [0.31.0] 2023-10-08
- Hide field Label.Text
- Remove aliased types and defaults in package shape
- Hide field Diagram.Caption
## [0.30.0] 2023-08-02
- Add shape.Labeled to simplify labeling any shape
- Group.WriteSVG writes all grouped shapes
## [0.29.0] 2023-08-02
- Add draw.DefaultFontFamily used in default classes
- Add shape.Hidden for hiding shapes
- Add shape.Anchor for linking shapes
## [0.28.0] 2023-08-25
- Add shape.Group and shape.Container
- shape.Card default width is 310px
- shape.Card takes optional note and text
## [0.27.0] 2023-08-20
- Add package draw/goviz for generating frame sequence diagrams
## [0.26.1] 2023-02-20
- Update dependencies
## [0.26.0] 2022-12-28
- Improve default link label positions
- Add shap.Card
- Consider a slice struct field of any type to be an
aggregate. Ie. before []*Something was considered an aggregate
whereas []Something was not. Now both are considered aggregates.
- Hide X, Y fields of shapes, use SetX, SetY and Position
## [0.25.0] 2022-04-21
- Draw relations of embedded interface fields
## [0.24.0] 2021-12-05
- Add Diagram.Note helper method
- Label shape supports linebreaks
- Add shapes Process, Store
## [0.23.0] 2021-09-04
- NewStyle does not take writer, defaults to ioutil.Discard.
Use Style.SetOutput
- Add SequenceDiagram.Return method for drawing dashed arrows
## [0.22.1] 2021-06-14
- Fix arrows in sequence diagram, bug introduced in v0.22.0
## [0.22.0] 2021-06-10
- Update dependencies
- Remove func draw.Inline(), moved to design as private
- Remove type Arrow, use Line
## [0.21.2] 2021-04-21
## [0.21.1] 2021-04-21
## [0.21.0] 2021-04-21
- Line and arrow Height and Width methods consider head and tail shapes
- Diamond.Position returns top left
- Triangle points upwards and Position returns top left
- Replace ActivityDiagram.If with Or when switching decision
- Replace ActivityDiagram.Then with Trans and add TransRight methods
- Activity diagram default spacing increased from 40 to 60
## [0.20.0] 2021-04-16
- Add Label.SetHref and Component.SetHref
- Rename type xy.Position to xy.Point
- Show relations between slices and structs in ClassDiagram
- Add SequenceDiagram.Skip method for adding a dashed spacing
- Replace draw.TagWriter with nexus.Printer
## [0.19.0] 2021-04-05
- Add labeled hexagon shape
- Fix label alignment
- Adjuster respects diagram style.Spacing
- NewDiagram returns a pointer to diagram
- Diagram variations embed reference to diagram
## [0.18.0] 2021-01-23
- Include slice methods in VRecord
- Remove double padding for record titles
- Improve label alignment in Diagram.Link method
## [0.17.0] 2020-12-16
- Fix Class diagram to show pointer receiver methods
- Add SequenceDiagram.Group method for grouping columns with a labeled text area
## [0.16.0] 2020-10-30
- Diagrams Stringer implementations no longer inline css, use Inline method
- Add VRecord.Slice method for slice composition and aggregates
## [0.15.1] 2020-10-27
- Fix missing relations in inlined class diagrams
## [0.15.0] 2020-10-27
- Diagrams implement stringer interface
- AdaptSize makes width and height +1 pixel
- Add Inline method to diagrams
- Add type ClassAttributes with CSS method for easy inlining in HTML
## [0.14.0] 2020-10-06
- Fix VRecord to show pointer methods if pointer to struct given
## [0.13.0] 2020-09-12
- Add shape.Internet
- Add default spacing to shape.Adjuster
- Move type shape.Style to package draw
- Rename NewSvg to NewSVG
## [0.12.0] 2020-09-09
### Changed
- Moved draw/shape/design package to draw/design
- Renamed type Svg to SVG
- Renamed type SvgWriter to SVGWriter
- Renamed WriteSvg to WriteSVG
## [0.11.0] 2020-03-17
### Changed
- Generic design.NewVRecord for both structs and interfaces
### Removed
- Specific methods for creating struct and interface methods.
## [0.10.0] 2020-02-03
### Added
- Ganttchart weekly view
- Cylinder and database shapes
- Func shape.SetClass for setting class of many shapes
### Fixed
- Component and rect labels use class + "-title"
## [0.9.0] 2020-01-02
### Added
- ActivityDiagram helper methods, e.g Start, Then, If and Exit
- Mark current day by default in gantt chart
### Changed
- Renamed Direction constants LR and RL to RightDir and LeftDir
- NewGanttChart constructor uses date.String
- Exposed TagWriter
- shape.Svg moved to draw.Svg
### Fixed
- Label positioned correctly in activity diagram for vertical arrows
## [0.8.0] 2019-12-18
### Added
- Aggregate relation when pointer to specific type is used
- Gantt chart
- Actor shape
### Changed
- Label is optional when creating links with func Link
- Hide Height, Width attributes in Diagram
- shape.NewDot defaults to radius 10
## [0.7.0] - 2019-12-15
### Changed
- Namespace from gregoryv/go-design to gregoryv/draw. Fix your imports
import "github.com/gregoryv/draw/shape/design"
## [0.6.0] - 2019-12-15
### Added
- Activity diagram examples
- Labeled links in plain diagrams
- State shape
- PlaceGrid to quickly place many shapes into a grid layout
## [0.5.0] - 2019-12-13
### Added
- Link method to generic diagram
- Rect, Dot, ExitDot and Component shapes
### Changed
- Label and circle has an edge
- Circle shape is stroked by default
## [0.4.0] - 2019-12-04
### Fixed
- Caption in sequence diagrams
### Changed
- Default color of records is white with pale lines
## [0.3.0] - 2019-10-12
### Fixed
- Arrows point to edge irrelevant of angle
### Added
- Diagrams have optional bottom centered caption
- Class diagram shows composition using diamond for tail
- Note shape with multiline support
### Changed
- Font size decoupled from class attributes
- Arrow for realizing interface is dashed
- Label and circle position is top left corner
- Hide methods realized by visible interfaces and structs
## [0.2.0] - 2019-10-03
### Changed
- All shapes can have a class
- Arrows in class diagrams attach to edge and point to center
### Fixed
- RightOf and LeftOf adjustments sets matching y position
- Use class for non self arrows
### Removed
- SvgWriterShape interface
## [0.1.0] - 2019-09-21
### Added
- Sequence diagram
- Class diagram
- Record shape with fields and methods
- Arrow, line and label shapes
License
MIT License
Copyright (c) 2019 Gregory Vinčić
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.