我写了一个在UML中验证Go语言包之间依赖关系的linter的故事

这篇文章是Go2 Advent Calender 2020第19天的文章。

今年,在我們的業務中,我們的團隊成員對於代碼中每個包的角色和它們之間的相互依賴關係的認識不一致,這導致了代碼的依賴關係變得複雜。我多次感到這樣的情況。如果包之間的依賴關係沒有整理好並變得複雜,我認為將會產生以下問題。

    • 外部のAPIと連携するためのパッケージにロジックが直接依存し、コードが具体的なことを知りすぎてしまい、メンテナンスがしにくくなってしまう

 

    複数のpackageの機能を跨いだテストが随所に書かれてしまい、パッケージを独立に開発・テストすることが難しくなってしまう

为了避免这种情况,我认为可以明确依赖关系并创建一个持续维护的机制。

使用UML来定义依赖关系。

我认为UML(统一建模语言)被广泛应用于描述系统的整体结构和依赖关系,并在软件开发中经常使用。

我也经常在工作中使用PlantUML来制作系统设计、顺序图和其他各种资料。

在这里,我们使用UML的方式来描述Go包之间的依赖关系。

非常抱歉我手头没有合适的代码,但在这种情况下,我会选择适当的软件包。

将该package所引入的所有package按照各自的角色进行分类,如下所示。

main : github.com/sodefrin/appengine-boilerplate
app : github.com/sodefrin/appengine-boilerplate/app
controller : github.com/sodefrin/appengine-boilerplate/app/controller
model : github.com/sodefrin/appengine-boilerplate/app/model/xo

proto : github.com/sodefrin/appengine-boilerplate/proto
proto : github.com/grpc-ecosystem/grpc-gateway/runtime
proto : github.com/golang/protobuf/descriptor
proto : github.com/golang/protobuf/proto
proto : github.com/golang/protobuf/ptypes/empty
proto : github.com/grpc-ecosystem/grpc-gateway/utilities
proto : google.golang.org/genproto/googleapis/api/annotations
proto : google.golang.org/grpc
proto : google.golang.org/grpc/codes
proto : google.golang.org/grpc/grpclog
proto : google.golang.org/grpc/status

util : github.com/sodefrin/appengine-boilerplate/log
util : go.uber.org/zap
    • main : コードのエントリーポイント。

 

    • app : 各種DIを実行し、サーバーを起動するコード。

 

    • controller : リクエストをハンドリングし、各種ロジックを実行するコード。

 

    • model : DBを操作するコード。

 

    • proto : GRPCのサーバの生成コード。

 

    util : loggerなどのどこから呼び出してもいいコード。

这些之间存在着像箭头一样的依存关系作为它们之间的依赖关系。

main -> app
app -> proto
app -> controller
app -> model
controller -> proto

main -> util
app -> util
controller -> util

使用PlantUML来绘制这种关系的图示,如下所示。

bLDBRiKW3DnpYbmWOTz5xq8IFse9R0H6RNhw0idxIK_DOnEPySnWOjiRfE5Zi2XVUPuMzZhn2fU8f4q8G1O9nfdHGGpE2AY2zl0hgXOcYUmArYlLTwdoXUsw3PfA_x1I8R9mbxufNkaiEqDspy_vebT8IyGW7DzXlsqRP0kGDFWIlEJ7i8omSDgIm76qfV1li-cOIT13homBEXI4T1SoMmVJNjl4qMeBr99wJvc0gVn0r8Q8.png

验证软件包的依赖关系

在此次创建的linter中,我们将根据前面提到的UML中的依赖关系定义来分析源代码,并验证是否存在违反import的情况。

举个例子,比如说,它会告诉你是否存在违规的导入项。

$ archi-checker -s $(go list ./... )
main.go:9:2: cannot import github.com/sodefrin/appengine-boilerplate/proto (proto) from github.com/sodefrin/appengine-boilerplate (main)

请使用以下链接进行参考:

尝试之后的结果。

目前,我正在業務中編寫的程式碼依賴關係使用UML進行定義,並嘗試運行上述的程式碼檢查工具,但出現了太多錯誤,無法修正。現實是殘酷的…

另外,UML的维护成本相当高,感觉还挺吃力的。

如果依赖关系在UML等中被明确化并共享,即使没有使用linter,只靠代码审查来指出问题是否足够呢?这是我个人的结论。

虽然如此,我认为定期整理和重新审视依赖关系的图示是有益的,所以如果有机会的话,可以尝试一下!

非常感谢您一直以来的陪伴。

bannerAds