programming/golang

Go 코드에서 UML 다이어그램 뽑아내기 – 개발자 생산성 200% UP!

jamie91 2025. 3. 7. 18:15

1. UML Diagram

1.1. Graphviz

# Latest release
go install github.com/ofabry/go-callvis@latest
# Development version
go install github.com/ofabry/go-callvis@master
go-callvis <target package>

 

적용 사례

1.2. PlantUML

go get github.com/jfeliu007/goplantuml/parser
go install github.com/jfeliu007/goplantuml/cmd/goplantuml@latest
goplantuml [-recursive] path/to/gofiles path/to/gofiles2

 

1.2.1. PlantUML 적용

PlantUML 적용

더보기
@startuml
namespace account {
    class Info << (S,Aquamarine) >> {
        + IdentityEndpoint string
        + Username string
        + Password string
        + DomainName string
        + TenantName string
        + CwsGroupKey string
        + Key string
        + Value string

        + Init() 
        + AddConfigInfo(in <font color=blue>interface</font>{}) error
        + AddAccessInfo(in <font color=blue>interface</font>{}) (string, error)
        + MakeKey(cwsGroupKey string, in <font color=blue>interface</font>{}) (string, error)
        + GetKey(infoMap <font color=blue>map</font>[string]string) (string, error)
        + GetAllList() <font color=blue>map</font>[string]bool
        + Execute(notify *control.ActionNotify) *control.ConfirmResult
        + DataListener() 
        + GetDefaultDuration(dataType string, workType string) time.Duration

    }
}

namespace blockStorage {
    class Data << (S,Aquamarine) >> {
        + ServiceClient *gophercloud.ServiceClient
        + VolumeListChan <font color=blue>chan</font> []*collect.Volume
        + Tracer trace.Tracer
        + Ctx context.Context

        + ListVolumes(projectId string, wg *sync.WaitGroup) 

    }
}

namespace client {
    class Info << (S,Aquamarine) >> {
        + ProviderClient *gophercloud.ProviderClient
        + DomainId string
        + DomainName string
        + ProjectId string
        + ProjectName string
        + UserName string
        + UserId string

        + NewIdentityClient(ctx context.Context) (*identity.Data, error)
        + NewComputeClient(ctx context.Context) (*instance.Data, error)
        + NewImageClient(ctx context.Context) (*image.Data, error)
        + NewNetworkClient(ctx context.Context) (*networking.Data, error)
        + NewVolumeClient(ctx context.Context) (*blockStorage.Data, error)
        + NewObjectClient(ctx context.Context) (*objectStorage.Data, error)
        + NewPlacementClient(ctx context.Context) (*placement.Data, error)
        + NewLoadBalancerClient(ctx context.Context) (*loadbalancer.Data, error)

    }
}

namespace compute {
    class Data << (S,Aquamarine) >> {
        + ServiceClient *gophercloud.ServiceClient
        + ServerWithExtList []ServerWithExt
        + ServerListChan <font color=blue>chan</font> []*collect.Server
        + PortListFromServerChan <font color=blue>chan</font> []*collect.Port
        + AvailabilityZoneListChan <font color=blue>chan</font> []*collect.AvailabilityZone
        + FlavorListChan <font color=blue>chan</font> []*collect.Flavor
        + Tracer trace.Tracer
        + Ctx context.Context

        + ListServers(projectId string, userId string, wg *sync.WaitGroup) 
        + ListAvailabilityZones(wg *sync.WaitGroup) 
        + ListFlavors(wg *sync.WaitGroup) 

    }
    class ServerWithExt << (S,Aquamarine) >> {
    }
}
"availabilityzones.ServerAvailabilityZoneExt" *-- "compute.ServerWithExt"
"diskconfig.ServerDiskConfigExt" *-- "compute.ServerWithExt"
"extendedstatus.ServerExtendedStatusExt" *-- "compute.ServerWithExt"
"servers.Server" *-- "compute.ServerWithExt"

namespace identity {
    class Data << (S,Aquamarine) >> {
        + ServiceClient *gophercloud.ServiceClient
        + DomainListChan <font color=blue>chan</font> []*collect.Domain
        + RegionListChan <font color=blue>chan</font> []*collect.Region
        + ServiceListChan <font color=blue>chan</font> []*collect.Service
        + UserListChan <font color=blue>chan</font> []*collect.User
        + GroupListChan <font color=blue>chan</font> []*collect.Group
        + UserGroupListChan <font color=blue>chan</font> UserGroupList
        + RoleListChan <font color=blue>chan</font> []*collect.Role
        + PolicyListChan <font color=blue>chan</font> []*collect.Policy
        + ProjectListChan <font color=blue>chan</font> []*collect.Project
        + Tracer trace.Tracer
        + Ctx context.Context

        + ListDomains(domainName string, wg *sync.WaitGroup) 
        + ListRegions(wg *sync.WaitGroup) 
        + ListServices(wg *sync.WaitGroup) 
        + ListUsers(domainId string, wg *sync.WaitGroup) 
        + ListGroups(domainId string, wg *sync.WaitGroup) 
        + ListUserGroup(wg *sync.WaitGroup) 
        + ListRoles(wg *sync.WaitGroup, accountInfo *account.Info) 
        + ListPolicies(wg *sync.WaitGroup) 
        + ListProjects(domainId string, projectName string, wg *sync.WaitGroup) 

    }
    class UserGroupList << (S,Aquamarine) >> {
        + UserList []*collect.User
        + GroupList []*collect.Group

    }
}

namespace image {
    class Data << (S,Aquamarine) >> {
        + ServiceClient *gophercloud.ServiceClient
        + ImageListChan <font color=blue>chan</font> []*collect.Image
        + Tracer trace.Tracer
        + Ctx context.Context

        + ListImages(wg *sync.WaitGroup) 

    }
}

namespace loadbalancer {
    class Data << (S,Aquamarine) >> {
        + ServiceClient *gophercloud.ServiceClient
        + LoadBalancerListChan <font color=blue>chan</font> []*collect.LoadBalancer
        + Tracer trace.Tracer
        + Ctx context.Context

        + ListLoadBalancer(projectId string, wg *sync.WaitGroup) 

    }
}

namespace main {
    class DBSchemaStruct << (S,Aquamarine) >> {
        - name string
        - age string

        - getCommon() string
        - setCommon() 

    }
    interface DbSchemaInterface  {
        - setCommon() 
        - getCommon() string

    }
    class OpenStackSchema << (S,Aquamarine) >> {
        + OpenStackName string

    }
}
"main.DBSchemaStruct" *-- "main.OpenStackSchema"

"main.DbSchemaInterface" <|-- "main.DBSchemaStruct"

namespace metadata {
    class Iam << (S,Aquamarine) >> {
        + Fetch(jobKey string) (*data.Data, error)

    }
    class Metadata << (S,Aquamarine) >> {
        + Fetch(accessInfoKey string) (*data.Data, error)

    }
}

namespace networking {
    class Data << (S,Aquamarine) >> {
        + ServiceClient *gophercloud.ServiceClient
        + NetworkListChan <font color=blue>chan</font> []*collect.Network
        + SubnetListChan <font color=blue>chan</font> []*collect.Subnet
        + RouterListChan <font color=blue>chan</font> []*collect.Router
        + SecurityGroupListChan <font color=blue>chan</font> []*collect.SecurityGroup
        + PortListChan <font color=blue>chan</font> []*collect.Port
        + PortList []*collect.Port
        + FloatingIpListChan <font color=blue>chan</font> []*collect.FloatingIp
        + Tracer trace.Tracer
        + Ctx context.Context

        + ListNetworks(projectId string, wg *sync.WaitGroup) 
        + ListSubnets(projectId string, wg *sync.WaitGroup) 
        + ListRouters(projectId string, wg *sync.WaitGroup) 
        + ListSecurityGroups(projectId string, wg *sync.WaitGroup) 
        + ListPorts(ch <font color=blue>chan</font> []*collect.Port, projectId string, wg *sync.WaitGroup) 
        + ListFloatingIps(projectId string, wg *sync.WaitGroup) 

    }
}

namespace objectStorage {
    class Data << (S,Aquamarine) >> {
        + ServiceClient *gophercloud.ServiceClient
        + ContainerList []*collect.OpenStackContainer
        + ContainerListChan <font color=blue>chan</font> []*collect.OpenStackContainer
        + ObjectListChan <font color=blue>chan</font> []*collect.Object
        + Tracer trace.Tracer
        + Ctx context.Context

        + ListContainers(domainId string, projectId string, wg *sync.WaitGroup) 
        + ListObjects(domainId string, projectId string, wg *sync.WaitGroup) 

    }
    interface d  {
    }
}

namespace openstack {
    class OpenStack << (S,Aquamarine) >> {
        + Agent agent.Agent

        + Init() 
        + Work() 
        + Release() 

    }
}

namespace placement {
    class Data << (S,Aquamarine) >> {
        + ServiceClient *gophercloud.ServiceClient
        + ResourceProviderList []*collect.ResourceProvider
        + ResourceProviderListChan <font color=blue>chan</font> []*collect.ResourceProvider
        + Tracer trace.Tracer
        + Ctx context.Context

        + ListResourceProviders(wg *sync.WaitGroup) 

    }
}
@enduml

Goland PlatUML 플러그인 사용해 보기

더보기

 

파일 생성

 

goplantuml 명령어 실행

 

puml 파일 선택

 

오류

 

PlantUML 설정 > Graphviz dot executable 에 dot 바이너리의 경로 추가

 

 

OS 별로 graphViz 다운 받는 방법 : https://plantuml.com/ko/graphviz-dot

 

 

2. Go Documentation

2.1. godoc library

godoc 은 개발자가 소스 내부에 작성한 주석을 웹 문서를 generate 하며,

특정 포트로 웹 브라우저에서 정리된 문서를 확인해 볼 수 있는 자동 문서화 서비스 입니다.

 

장점: 단순 주석을 통해 웹 브라우저에서 정리된 문서를 즉각 확인해 볼 수 있습니다.

단점:

  • 특정 포트에서 서비스해야한다는 점.
    • 즉, 정적 웹 문서를 생성하는게 아닙니다.
    • 웹 페이지를 이쁘게 만들어주는 js 파일과 css 파일이 godoc cli application 내부에 정의되어 있으며,
    • godoc 바이너리를 실행해야지만 디자인 및 기능이 적용이 되는 로직입니다.
    • html 파일로 패키지별 export 할 수 있지만, css 와 js 는 수동으로 작업해만 이쁜 문서가 될 수 있습니다.
      • 개발자 편리성을 고려해 보았을 때 수동 작업을 최소화 해야 하기 때문에 해당 작업은 고려 대상이 아닌 것으로 판단 됩니다.

godoc package - golang.org/x/tools/godoc - Go Packages

 

godoc 설치

go install golang.org/x/tools/cmd/godoc

 

godoc 실행

godoc -http=:6060

 

Main 페이지 (http://localhost:6060/pkg)

 

Package 별 문서 (http://localhost:6060/pkg/agent_service/agent/)

2.2. Goland documentation (Goland 빠른 문서)

2.2.1. Goland documentation 활용

 

 

2.3. Goland documentation x Goanno plugin

2.3.1. Goanno 플러그인

Goanno 플러그인

  • 주석 템플릿을 자동 생성 기능을 제공하는 Intellij & Goland 플러그인

 

2.3.2. Goanno 플러그인 사용전

 

 

 

2.3.3. Goanno 플러그인 사용후

728x90
반응형