Coca - 系统重构与分析工具箱
Coca 是一个用于系统重构、系统迁移和系统分析的工具箱。它可以分析代码中的测试坏味道、模块化分析、行数统计、分析调用与依赖、Git 分析以及自动化重构等。
相关工具: Coco 是一个高效的DevOps分析和自动建议工具。
Kotlin版本: Chapi
迁移指南(中文版): 《系统重构与迁移指南》
重构建模:
- 支持语言: Java(完整功能)
功能列表:
可用命令:
analysis 分析代码
api 从注释中扫描HTTP API
arch 工程包可视化
bs 生成坏味道列表和建议
call 显示特定方法的调用图
cloc 进行代码行数统计,并估算复杂度
concept 从源代码构建领域概念
count 统计引用最多的函数
evaluate 评估代码情况和重构工作量
git 分析Git提交历史,以统计修订次数、摘要及建议
help 获取任意命令的帮助
rcall 逆向调用图可视化
refactor 自动重构代码
suggest 从代码中找到可用的设计模式
tbs 生成测试坏味道
todo 扫描所有待办事项,并按时间列出
version 版本
开始使用
要求: graphviz 用于将dot文件转换为图像(如svg, png)
获取coca的最简单方法是使用预构建的发布二进制文件,这些文件可在发布页面上获取,适用于OSX、Linux、Windows。
你也可以自己安装:
go install github.com/modernizing/coca@latest
用法
分析
coca analysis
架构
coca arch
Android Studio Gradle DSL 模块(合并头部)
命令: coca arch -x "com.android.tools.idea.gradle.dsl" -H true
Android Studio Gradle DSL 模块元素部分:
命令: coca arch -x "com.android.tools.idea.gradle.dsl.parser.elements"
查找坏味道
coca bs -s type
示例结果:
{
"dataClass": [
{
"File": "examples/api/BookController.java",
"BS": "dataClass"
}
],
"lazyElement": [
{
"File": "examples/api/model/BookRepresentaion.java",
"BS": "lazyElement"
}
]
}
代码行数统计
coca cloc
结果:
───────────────────────────────────────────────────────────────────────────────
语言 文件数 行数 空行 注释行 代码 复杂度
───────────────────────────────────────────────────────────────────────────────
Go 58 31763 7132 890 23741 2847
Java 44 971 208 21 742 62
Markdown 8 238 75 0 163 0
Gherkin Specificati… 2 32 2 16 14 0
Document Type Defin… 1 293 36 0 257 0
License 1 201 32 0 169 0
SQL 1 2 0 0 2 0
SVG 1 199 0 34 165 0
Shell 1 3 1 1 1 0
XML 1 13 0 0 13 0
gitignore 1 61 8 4 49 0
───────────────────────────────────────────────────────────────────────────────
总计 119 33776 7494 966 25316 2909
───────────────────────────────────────────────────────────────────────────────
估算开发成本: $803,822
估算进度: 14.120551 个月
估算需求人员: 6.743156
───────────────────────────────────────────────────────────────────────────────
结果输出为json:
coca cloc --by-file --format json
按目录统计代码行数
coca cloc ~/intellij-community/android/ --by-directory --include-ext=java,kt --not-match=".*(Test|Tests)\.(kt|java)"
结果输出为csv:
模块,总结
adt-branding,169
adt-testutils,257
adt-ui,21987
adt-ui-model,3450
android,361270
android-adb,497
android-common,3280
android-debuggers,3030
android-kotlin,8816
android-lang,24796
android-lang-databinding,6392
android-layout-inspector,2533
...
代码行数Top文件
coca cloc ~/intellij-community/android/designer/src/com/android/tools/idea --top-file --top-size 10
输出到: coca_reporter/sort_cloc.json
还有:
| 长度 | 复杂度 | 文件路径 |
|--------|------------|-----------------------------------|
| 1642 | 236 | ConstraintLayoutHandler.java |
| 1492 | 375 | ConstraintComponentUtilities.java |
| 1189 | 166 | CommonActions.java |
| 1184 | 325 | ConstraintWidget.java |
| 1169 | 129 | SingleWidgetView.java |
| 1115 | 213 | ScoutArrange.java |
| 1097 | 281 | ScoutWidget.java |
| 1081 | 224 | 3d/Rasterize.java |
| 1016 | 159 | LayoutlibSceneManager.java |
| 1014 | 220 | TimeLinePanel.java |
构建依赖树
coca call -c com.phodal.pholedge.book.BookController.createBook -r com.phodal.pholedge.
示例结果:
识别Spring API
coca api -f
带计数
coca api -r com.phodal.pholedge. -c
或多个包:
coca api -r com.macro.mall.demo.controller.,com.zheng.cms.admin.,com.phodal.pholedge -c
+------+--------+------------------------------------------------+------------------------------------------------------------------------+
| 大小 | 方法 | URI | 调用方 |
+------+--------+------------------------------------------------+------------------------------------------------------------------------+
| 36 | GET | /aliyun/oss/policy | controller.OssController.policy |
| 21 | POST | /aliyun/osscallback | controller.OssController.callback |
| 17 | GET | /subject/list | controller.CmsSubjectController.getList |
| 17 | GET | /esProduct/search | search.controller.EsProductController.search |
| 17 | GET | /order/list | controller.OmsOrderController.list |
| 17 | GET | /productAttribute/list/{cid} | controller.PmsProductAttributeController.getList |
| 17 | GET | /productCategory/list/{parentId} | controller.PmsProductCategoryController.getList |
| 17 | GET | /brand/list | controller.PmsBrandController.getList |
| 17 | GET | /esProduct/search/simple | search.controller.EsProductController.search |
+------+--------+------------------------------------------------+------------------------------------------------------------------------+
Git分析
coca git -t
结果:
+---------------------------------------------------------------------------------------------------------------------+-----------+-------------+
| ENTITYNAME | REVSCOUNT | AUTHORCOUNT |
+---------------------------------------------------------------------------------------------------------------------+-----------+-------------+
| build.gradle | 1326 | 36 |
| src/asciidoc/index.adoc | 239 | 20 |
| build-spring-framework/resources/changelog.txt | 187 | 10 |
| spring-core/src/main/java/org/springframework/core/annotation/AnnotationUtils.java | 170 | 10 |
| spring-beans/src/main/java/org/springframework/beans/factory/support/DefaultListableBeanFactory.java | 159 | 15 |
| src/docs/asciidoc/web/webmvc.adoc | 121 | 24 |
| spring-context/src/main/java/org/springframework/context/annotation/ConfigurationClassParser.java | 118 | 9 |
| src/dist/changelog.txt | 118 | 9 |
| spring-webmvc/src/main/java/org/springframework/web/servlet/config/annotation/WebMvcConfigurationSupport.java | 116 | 15 |
| spring-beans/src/main/java/org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java | 113 | 15 |
| spring-web/src/main/java/org/springframework/http/HttpHeaders.java | 111 | 18 |
| src/docs/asciidoc/web/webflux.adoc | 108 | 21 |
| spring-core/src/main/java/org/springframework/core/annotation/AnnotatedElementUtils.java | 107 | 9 |
| spring-test/spring-test.gradle | 105 | 7 |
| spring-webmvc/src/main/java/org/springframework/web/servlet/mvc/method/annotation/RequestMappingHandlerAdapter.java | 105 | 13 |
| spring-messaging/src/main/java/org/springframework/messaging/simp/stomp/StompBrokerRelayMessageHandler.java | 101 | 12 |
| spring-web/src/main/java/org/springframework/web/client/RestTemplate.java | 98 | 17 |
| spring-webmvc/src/main/java/org/springframework/web/servlet/resource/ResourceHttpRequestHandler.java | 96 | 14 |
| org.springframework.core/src/main/java/org/springframework/core/convert/TypeDescriptor.java | 93 | 4 |
| spring-core/src/main/java/org/springframework/core/ResolvableType.java | 92 | 10 |
+---------------------------------------------------------------------------------------------------------------------+-----------+-------------+
概念分析器
coca concept
结果示例:
+------------------+--------+
| WORDS | COUNTS |
+------------------+--------+
| context | 590 |
| resolve | 531 |
| path | 501 |
| content | 423 |
| code | 416 |
| resource | 373 |
| property | 372 |
| session | 364 |
| attribute | 349 |
| properties | 343 |
| headers | 330 |
+------------------+--------+
计数引用
coca count
结果:
+------------+--------------------------------------------------------------------------+
| REFS COUNT | METHOD |
+------------+--------------------------------------------------------------------------+
| 2 | com.phodal.pholedge.book.BookRepository.byId |
| 2 | com.phodal.pholedge.book.model.Book.toRepresentation |
| 2 | com.phodal.pholedge.book.BookRepository.save |
| 2 | com.phodal.coca.analysis.JavaCallApp.parse |
| 2 | com.phodal.pholedge.book.BookRepository.save |
| 2 | com.phodal.coca.analysis.JavaCallApp.parse |
| 1 | com.phodal.pholedge.book.model.Book.save |
| 1 | evolution.analysis.jv.calls.JavaCallVisitor.parseNewType |
| 1 | evolution.analysis.jv.calls.JavaCallVisitor.isNotSpecialNewWord |
| 1 | com.phodal.pholedge.book.BookMapper.byId |
| 1 | com.phodal.pholedge.book.BookService.updateBook |
| 1 | com.phodal.pholedge.book.BookService.getBooksLists |
| 1 | com.phodal.pholedge.book.BookService.getBookById |
| 1 | com.phodal.pholedge.book.BookMapper.doSave |
| 1 | com.phodal.pholedge.book.BookMapper.list |
| 1 | com.phodal.pholedge.book.BookService.createBook |
| 1 | com.phodal.pholedge.book.BookFactory.create |
| 1 | com.phodal.pholedge.book.BookRepository.list |
| 1 | com.phodal.pholedge.book.model.Book.create |
+------------+--------------------------------------------------------------------------+
反向调用图
coca rcall -c org.bytedeco.javacpp.tools.TokenIndexer.get
结果:
有向图 G {
边 [方向="返回"];
"org.bytedeco.javacpp.tools.Parser.extern" -> "org.bytedeco.javacpp.tools.Parser.declarations";
"org.bytedeco.javacpp.tools.Parser.declarations" -> "org.bytedeco.javacpp.tools.Parser.extern";
...
}
自动重构
支持:
- 重命名
- 移动
- 移除未使用的导入
- 移除未使用的类
coca refactor -R rename.coca -p src/main
coca refactor -m move.config -p .
评估
coca evaluate
Arduino 结果(旧版):
+--------------------------------+-------+-----------------------+-------+-----------+
| 类型 | 计数 | 紧急 | 总计 | 比率 |
+--------------------------------+-------+-----------------------+-------+-----------+
| 可为空 / 返回空值 | 0 | 方法 | 1615 | 0.00% |
| 工具类 | 7 | 类 | 252 | 2.78% |
| 静态方法 | 0 | 方法 | 1615 | 0.43% |
| 平均方法数 | 1615 | 方法/类 | 252 | 6.408730 |
| 方法数量标准差 | 1615 | 类 | - | 7.344917 |
| 平均方法长度 | 13654 | 不含获取器/设置器 | 1100 | 12.412727 |
| 方法长度标准差 | 1615 | 方法 | - | 20.047092 |
+--------------------------------+-------+-----------------------+-------+-----------+
新版:
| 类型 | 类型数量 | 紧急 | 总计 | 比率 |
|--------------------------------|---------|----------------------|-------|---------------------|
| 可为空 / 返回空值 | 0 | 方法 | 6 | 0.00% |
| 工具类 | 0 | 类 | 14 | 0.00% |
| 静态方法 | 1 | 方法 | 6 | 0.00% |
| 平均方法数 | 6 | 方法/类 | 14 | 0.428571 |
| 方法数量标准差 | 6 | 类 | - | 0.646206 |
| 平均方法长度 | 0 | 不含获取器/设置器 | 0 | NaN |
| 方法长度标准差 | 0 | 方法 | - | NaN |
Evaluate.json 示例
{
"可为空": {
"项目": [
"nonnull.Name.testNull",
"nonnull.Name.orElseNull",
"org.ofbiz.base.util.UtilURL.fromResource",
"org.ofbiz.base.util.UtilURL.getOfbizHomeRelativeLocationFromFilePath",
"study.huhao.demo.adapters.outbound.persistence.blog.BlogPO.toDomainModel",
"study.huhao.demo.adapters.outbound.persistence.blog.BlogPO.toDomainModel",
"study.huhao.demo.adapters.outbound.persistence.blog.BlogPO.of",
"study.huhao.demo.infrastructure.persistence.blog.BlogPO.convertDomain"
]
},
"服务摘要": {
"生命周期图": null,
"返回类型图": {
"BookRepresentaion": [
"com.phodal.pholedge.book.BookService.getBookById",
"com.phodal.pholedge.book.BookService.updateBook"
]
},
"相关方法": null
},
"工具类摘要": {},
"摘要": {
"工具类数": 1,
"类数": 64,
"方法数": 161,
"静态方法数": 19
}
}
待办事项
coca todo
结果:
+------------+-----------------+--------------------------------+--------------------------------------------------------------------------------------+------+ | DATE | AUTHOR | MESSAGES | FILENAME | LINE | +------------+-----------------+--------------------------------+--------------------------------------------------------------------------------------+------+ | 2019-12-09 | Cristian Maglie | happens on macosx, don't know | app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCellJPanel.java | 118 | | | | why | | | | 2019-12-09 | Cristian Maglie | Make this a method of Theme | app/src/cc/arduino/contributions/libraries/ui/ContributedLibraryTableCellJPanel.java | 233 | | 2019-12-09 | Cristian Maglie | Do a better job in refreshing | app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java | 241 | | | | only the needed element | | | | 2019-12-09 | Cristian Maglie | Do a better job in refreshing | app/src/cc/arduino/contributions/libraries/ui/LibraryManagerUI.java | 273 | | | | only the needed element | | | | 2019-12-09 | Cristian Maglie | Make this a method of Theme | app/src/cc/arduino/contributions/libraries/ui/MultiLibraryInstallDialog.java | 149 | | 2019-12-09 | Cristian Maglie | happens on macosx, don't know | app/src/cc/arduino/contributions/packages/ui/ContributedPlatformTableCellJPanel.java | 183 | | | | why | | | | 2019-12-09 | Cristian Maglie | show error | app/src/processing/app/Base.java | 1440 | | 2019-12-09 | Cristian Maglie | error when importing. ignoring | app/src/processing/app/Base.java | 2423 | | | | :( | | | | 2019-12-09 | Cristian Maglie | Improve / move error handling | app/src/processing/app/Editor.java | 1541 | | 2019-12-09 | Cristian Maglie | Should be a Theme value? | app/src/processing/app/EditorHeader.java | 78 | | 2019-12-09 | Cristian Maglie | Should be a Theme value? | app/src/processing/app/EditorStatus.java | 73 | | 2019-12-09 | Cristian Maglie | Improve decoupling | app/src/processing/app/EditorTab.java | 465 | +------------+-----------------+--------------------------------+--------------------------------------------------------------------------------------+------+```
Suggest
coca suggest
results:
+--------+------------------+--------------------------------+
| CLASS | PATTERN | REASON |
+--------+------------------+--------------------------------+
| Insect | factory | too many constructor |
| Bee | factory, builder | complex constructor, too |
| | | many constructor, too many |
| | | parameters |
+--------+------------------+--------------------------------+
Test Bad Smells
coca tbs
results
+---------------------+---------------------------------------------------------------+------+
| TYPE | FILENAME | LINE |
+---------------------+---------------------------------------------------------------+------+
| DuplicateAssertTest | app/test/cc/arduino/i18n/ExternalProcessOutputParserTest.java | 107 |
| DuplicateAssertTest | app/test/cc/arduino/i18n/ExternalProcessOutputParserTest.java | 41 |
| DuplicateAssertTest | app/test/cc/arduino/i18n/ExternalProcessOutputParserTest.java | 63 |
| RedundantPrintTest | app/test/cc/arduino/i18n/I18NTest.java | 71 |
| RedundantPrintTest | app/test/cc/arduino/i18n/I18NTest.java | 72 |
| RedundantPrintTest | app/test/cc/arduino/i18n/I18NTest.java | 77 |
| DuplicateAssertTest | app/test/cc/arduino/net/PACSupportMethodsTest.java | 19 |
| DuplicateAssertTest | app/test/processing/app/macosx/SystemProfilerParserTest.java | 51 |
| DuplicateAssertTest | app/test/processing/app/syntax/PdeKeywordsTest.java | 41 |
| DuplicateAssertTest | app/test/processing/app/tools/ZipDeflaterTest.java | 57 |
| DuplicateAssertTest | app/test/processing/app/tools/ZipDeflaterTest.java | 83 |
| DuplicateAssertTest | app/test/processing/app/tools/ZipDeflaterTest.java | 109 |
+---------------------+---------------------------------------------------------------+------+
Find unused deps
coca deps -p _fixtures/deps/maven_sample
results:
+---------------------------+----------------------------------------+---------+
| GROUPID | ARTIFACTID | SCOPE |
+---------------------------+----------------------------------------+---------+
| org.flywaydb | flyway-core | |
| mysql | mysql-connector-java | runtime |
| org.springframework.cloud | spring-cloud-starter-contract-verifier | test |
+---------------------------+----------------------------------------+---------+
Showcases
Android Studio Analysis Examples. Call with lookup
: coca call -l
Roadmap
- bad smell support
- sort method size
- type
- longParameterList
- longMethod
- repeatedSwitches
- complexIf
- largeClass
- refusedBequest
- dataClass
- CLOC
- HTTP API Visualization
- Spring Support
- @Service Support
- API Call Size
- Git
- Revs Counts
- Summary
- git-quick-stats
- Concept
- words NLP
- to domain
- Call & rcall graph
- Count Refs
- AutoRefactor
- remove unused
- move files
- Evaluate
- nullable count
- static count
- method num /length count
- Todo Summary
- Todo with History & Author
- Suggest API for Design Patterns
- factory pattern
- strategy
- builder
- cycle-deps -> adapter / agency
- bad patterns
- singleton
- Evaluate API
- Average Method Length
- Average Class Method Count
- Tests
- Testable?
- Test badsmell -> list [https://testsmells.github.io/pages/testsmells.html]
- IgnoreTest: @Ingore
- EmptyTest: not call in test
- RedundantPrintTest: system.out.println
- SleepyTest: Time.sleep
- RedundantAssertionTest: assertTrue(True)
- UnknownTest: not assert
- DuplicateAssertTest: assert > 5
- TestersOnly: method only call by test
- CrossBorderTest: test method which not in system
- General Fixture: JUnit classes having at least one method not using the entire test fixture defined in the setUp() method
- Arch
- Architecture Visualization
- Architecture Guard
- DSL Design
- Tech Debt from Source Code
- auto create story
- TBD
- Comment Analysis
- incorrect comment ? http://das.encs.concordia.ca/uploads/2018/02/Maldonado_thesis.pdf
- Comment Analysis
Online Code Analysis-
WASM support -
expose WASM API -
GitHub search code
-
-
Pluggable-
plugin support (Windows Issues)
-
- Dependence Analysis
- Deps Related Counts
- 3rd-party analysis XML or Groovy Scripts
- Groovy Support
- migrate to Golang Styles
- Story Cmd
- Auto create refactor story
- Clean Code Suggest
- JavaScript Version clean-code-javascript
- More CodeSmells
- Source DesigniteJava
Documents Todo:
- Docs
- Lifecycle for new projects: evaluate (cloc, bad smell, api, git, todo) -> design -> patterns (suggest) -> refactoring ()
- Date Collections
- monolithic
- microservice
- big data
Tech Debt
- Test for Windows
- Duplicate Code
- cmd/ -> user builder to refactoring
Dev
Install Go
brew install go
Env
export GOROOT=/usr/local/opt/go/libexec
export GOPATH=$HOME/.go
export PATH=$PATH:$GOROOT/bin:$GOPATH/bin
clone
git clone https://github.com/modernizing/coca
Test Frameworks
go get github.com/onsi/ginkgo
go get github.com/onsi/gomega
License
Arch based on Tequila
Git Analysis inspired by Code Maat
Test bad smells inspired by Test Smell Examples
@ 2019 A Phodal Huang's Idea. This code is distributed under the MPL license. See LICENSE
in this directory.