├── go.mod ├── LICENSE ├── src ├── Makefile ├── generate-td_test.go └── generate-td.go ├── go.sum ├── README.md └── docs ├── article_german.md └── article.md /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/ms1963/TechnicalDebtRecords 2 | 3 | go 1.23 4 | 5 | require ( 6 | github.com/phpdave11/gofpdf v1.4.2 7 | github.com/xuri/excelize/v2 v2.8.1 8 | ) 9 | 10 | require ( 11 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 // indirect 12 | github.com/richardlehane/mscfb v1.0.4 // indirect 13 | github.com/richardlehane/msoleps v1.0.4 // indirect 14 | github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d // indirect 15 | github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 // indirect 16 | golang.org/x/crypto v0.28.0 // indirect 17 | golang.org/x/net v0.30.0 // indirect 18 | golang.org/x/text v0.19.0 // indirect 19 | ) 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Michael Stal 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Technical Debt Record (TDR) Generator Tool 2 | 3 | # Variables 4 | BINARY_NAME=generate-td 5 | GO_FILES=generate-td.go 6 | 7 | # Default target 8 | .PHONY: all 9 | all: build 10 | 11 | # Initialize Go module if not already initialized 12 | .PHONY: init 13 | init: 14 | @echo "Initializing Go module..." 15 | go mod init technical_debt_generator || echo "Go module already initialized." 16 | @echo "Go module initialization complete." 17 | 18 | # Download and add dependencies 19 | .PHONY: deps 20 | deps: init 21 | @echo "Adding required dependencies..." 22 | go get github.com/phpdave11/gofpdf 23 | go get github.com/xuri/excelize/v2 24 | @echo "Dependencies added successfully." 25 | 26 | # Tidy up the Go module (optional) 27 | .PHONY: tidy 28 | tidy: deps 29 | @echo "Tidying up Go modules..." 30 | go mod tidy 31 | @echo "Go modules tidied successfully." 32 | 33 | # Build the executable 34 | .PHONY: build 35 | build: deps 36 | @echo "Building $(BINARY_NAME)..." 37 | go build -o $(BINARY_NAME) $(GO_FILES) 38 | @echo "Build completed. Executable: $(BINARY_NAME)" 39 | 40 | # Clean the executable and Go module files 41 | .PHONY: clean 42 | clean: 43 | @echo "Cleaning up..." 44 | rm -f $(BINARY_NAME) 45 | rm -f go.mod go.sum 46 | @echo "Clean completed." 47 | 48 | # Run the tool (optional) 49 | .PHONY: run 50 | run: build 51 | @echo "Running $(BINARY_NAME)..." 52 | ./$(BINARY_NAME) 53 | 54 | # Test the application 55 | .PHONY: test 56 | test: 57 | @echo "Running tests..." 58 | go test ./... 59 | @echo "Tests completed." 60 | -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/boombuler/barcode v1.0.0/go.mod h1:paBWMcWSl3LHKBqUq+rly7CNSldXjb2rDl3JlRe0mD8= 2 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 3 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 4 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 5 | github.com/jung-kurt/gofpdf v1.0.0/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= 6 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826 h1:RWengNIwukTxcDr9M+97sNutRR1RKhG96O6jWumTTnw= 7 | github.com/mohae/deepcopy v0.0.0-20170929034955-c48cc78d4826/go.mod h1:TaXosZuwdSHYgviHp1DAtfrULt5eUgsSMsZf+YrPgl8= 8 | github.com/phpdave11/gofpdf v1.4.2 h1:KPKiIbfwbvC/wOncwhrpRdXVj2CZTCFlw4wnoyjtHfQ= 9 | github.com/phpdave11/gofpdf v1.4.2/go.mod h1:zpO6xFn9yxo3YLyMvW8HcKWVdbNqgIfOOp2dXMnm1mY= 10 | github.com/phpdave11/gofpdi v1.0.12/go.mod h1:vBmVV0Do6hSBHC8uKUQ71JGW+ZGQq74llk/7bXwjDoI= 11 | github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 12 | github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 13 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 14 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 15 | github.com/richardlehane/mscfb v1.0.4 h1:WULscsljNPConisD5hR0+OyZjwK46Pfyr6mPu5ZawpM= 16 | github.com/richardlehane/mscfb v1.0.4/go.mod h1:YzVpcZg9czvAuhk9T+a3avCpcFPMUWm7gK3DypaEsUk= 17 | github.com/richardlehane/msoleps v1.0.1/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= 18 | github.com/richardlehane/msoleps v1.0.3 h1:aznSZzrwYRl3rLKRT3gUk9am7T/mLNSnJINvN0AQoVM= 19 | github.com/richardlehane/msoleps v1.0.3/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= 20 | github.com/richardlehane/msoleps v1.0.4 h1:WuESlvhX3gH2IHcd8UqyCuFY5yiq/GR/yqaSM/9/g00= 21 | github.com/richardlehane/msoleps v1.0.4/go.mod h1:BWev5JBpU9Ko2WAgmZEuiz4/u3ZYTKbjLycmwiWUfWg= 22 | github.com/ruudk/golang-pdf417 v0.0.0-20181029194003-1af4ab5afa58/go.mod h1:6lfFZQK844Gfx8o5WFuvpxWRwnSoipWe/p622j1v06w= 23 | github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 24 | github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= 25 | github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= 26 | github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53 h1:Chd9DkqERQQuHpXjR/HSV1jLZA6uaoiwwH3vSuF3IW0= 27 | github.com/xuri/efp v0.0.0-20231025114914-d1ff6096ae53/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= 28 | github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d h1:llb0neMWDQe87IzJLS4Ci7psK/lVsjIS2otl+1WyRyY= 29 | github.com/xuri/efp v0.0.0-20240408161823-9ad904a10d6d/go.mod h1:ybY/Jr0T0GTCnYjKqmdwxyxn2BQf2RcQIIvex5QldPI= 30 | github.com/xuri/excelize/v2 v2.8.1 h1:pZLMEwK8ep+CLIUWpWmvW8IWE/yxqG0I1xcN6cVMGuQ= 31 | github.com/xuri/excelize/v2 v2.8.1/go.mod h1:oli1E4C3Pa5RXg1TBXn4ENCXDV5JUMlBluUhG7c+CEE= 32 | github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05 h1:qhbILQo1K3mphbwKh1vNm4oGezE1eF9fQWmNiIpSfI4= 33 | github.com/xuri/nfp v0.0.0-20230919160717-d98342af3f05/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= 34 | github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7 h1:hPVCafDV85blFTabnqKgNhDCkJX25eik94Si9cTER4A= 35 | github.com/xuri/nfp v0.0.0-20240318013403-ab9948c2c4a7/go.mod h1:WwHg+CVyzlv/TX9xqBFXEZAuxOPxn2k1GNHwG41IIUQ= 36 | golang.org/x/crypto v0.19.0 h1:ENy+Az/9Y1vSrlrvBSyna3PITt4tiZLf7sgCjZBX7Wo= 37 | golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= 38 | golang.org/x/crypto v0.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= 39 | golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= 40 | golang.org/x/image v0.0.0-20190910094157-69e4b8554b2a/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= 41 | golang.org/x/image v0.14.0 h1:tNgSxAFe3jC4uYqvZdTr84SZoM1KfwdC9SKIFrLjFn4= 42 | golang.org/x/image v0.14.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE= 43 | golang.org/x/net v0.21.0 h1:AQyQV4dYCvJ7vGmJyKki9+PBdyvhkSd8EIx/qb0AYv4= 44 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= 45 | golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= 46 | golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= 47 | golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= 48 | golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ= 49 | golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= 50 | golang.org/x/text v0.19.0 h1:kTxAhCbGbxhK0IwgSKiMO5awPoDQ0RpfiVYBfK860YM= 51 | golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= 52 | gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 53 | gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Technical Debt Record (TDR) Generator 2 | 3 | ## Table of Contents 4 | - [Introduction](#introduction) 5 | - [What is a Technical Debt Record (TDR)?](#what-is-a-technical-debt-record-tdr) 6 | - [Motivation for TDRs](#motivation-for-tdrs) 7 | - [Fields in a TDR](#fields-in-a-tdr) 8 | - [Benefits of TDRs](#benefits-of-tdrs) 9 | - [Relation to Architecture Decision Records (ADRs)](#relation-to-architecture-decision-records-adrs) 10 | - [Using the TDR Generator Program](#using-the-tdr-generator-program) 11 | - [Prerequisites](#prerequisites) 12 | - [Installation](#installation) 13 | - [Usage](#usage) 14 | - [Best Practices](#best-practices) 15 | - [Version Control Integration](#version-control-integration) 16 | - [License](#license) 17 | 18 | ## Introduction 19 | 20 | In software development, managing technical debt is crucial for maintaining code quality, ensuring scalability, and facilitating future enhancements. This repository provides a Go-based tool to generate **Technical Debt Records (TDRs)** in various formats, aiding teams in systematically documenting and addressing technical debt within their projects. 21 | 22 | ## What is a Technical Debt Record (TDR)? 23 | 24 | A **Technical Debt Record (TDR)** is a structured document that captures details about technical debt within a software project. Technical debt refers to the implied cost of additional rework caused by choosing an easy solution now instead of using a better approach that would take longer. TDRs help teams track, analyze, and prioritize technical debt, ensuring informed decision-making and strategic planning for codebase improvements. 25 | 26 | ## Motivation for TDRs 27 | 28 | Technical debt, if left unmanaged, can accumulate over time, leading to increased maintenance costs, reduced agility, and potential system failures. The primary motivations for maintaining TDRs include: 29 | 30 | - **Visibility:** Providing clear insights into existing technical debt. 31 | - **Accountability:** Assigning responsibility for addressing specific debts. 32 | - **Prioritization:** Evaluating the impact and urgency of each debt item. 33 | - **Strategic Planning:** Informing long-term architectural and development decisions. 34 | 35 | By systematically recording technical debt, teams can proactively manage and mitigate its adverse effects on the project. 36 | 37 | ## Fields in a TDR 38 | 39 | A comprehensive TDR encompasses several fields, each detailing specific aspects of the technical debt. Below are the primary fields included in the TDR generated by this tool: 40 | 41 | 1. **Title:** A concise name for the technical debt. 42 | 2. **Author:** The individual who identified or is documenting the debt. 43 | 3. **Version:** The version of the project or component where the debt exists. 44 | 4. **Date:** The date when the debt was identified or recorded. 45 | 5. **State:** The current workflow stage of the technical debt (e.g., Identified, Analyzed, Approved, In Progress, Resolved, Closed, Rejected). 46 | 6. **Relations:** Links to other related TDRs, establishing connections between different debt items. 47 | 7. **Summary:** A brief overview explaining the nature and context of the technical debt. 48 | 8. **Context:** Detailed background information, including why the debt was incurred (e.g., rushed deadlines, outdated technologies). 49 | 9. **Impact:** 50 | - **Technical Impact:** How the debt affects system performance, scalability, maintainability, etc. 51 | - **Business Impact:** The repercussions on business operations, customer satisfaction, risk levels, etc. 52 | 10. **Symptoms:** Observable signs indicating the presence of the technical debt (e.g., frequent bugs, slow performance). 53 | 11. **Severity:** The criticality level of the debt (Critical, High, Medium, Low). 54 | 12. **Potential Risks:** Possible adverse outcomes if the debt remains unaddressed (e.g., security vulnerabilities, increased costs). 55 | 13. **Proposed Solution:** Recommended actions or strategies to resolve the debt. 56 | 14. **Cost of Delay:** Consequences of postponing the resolution of the debt. 57 | 15. **Effort to Resolve:** Estimated resources, time, and effort required to address the debt. 58 | 16. **Dependencies:** Other tasks, components, or external factors that the resolution of the debt depends on. 59 | 17. **Additional Notes:** Any other relevant information or considerations related to the debt. 60 | 61 | ## Benefits of TDRs 62 | 63 | Maintaining TDRs offers several advantages to software development teams: 64 | 65 | - **Improved Code Quality:** By identifying and addressing technical debt, teams can enhance the overall quality and reliability of the codebase. 66 | - **Enhanced Project Planning:** TDRs provide valuable data for sprint planning, backlog prioritization, and resource allocation. 67 | - **Risk Mitigation:** Understanding the potential risks associated with technical debt allows teams to proactively address issues before they escalate. 68 | - **Knowledge Sharing:** TDRs serve as documentation that can be referenced by current and future team members, fostering a shared understanding of the project's technical landscape. 69 | - **Strategic Decision-Making:** Comprehensive records enable informed decisions regarding when to invest in refactoring, upgrading technologies, or implementing new features. 70 | 71 | ## Relation to Architecture Decision Records (ADRs) 72 | 73 | **Architecture Decision Records (ADRs)** are documents that capture important architectural decisions made during a project's lifecycle. They provide context and rationale behind choices that shape the system's structure and behavior. 74 | 75 | **Technical Debt Records (TDRs)** are motivated by ADRs in the following ways: 76 | 77 | - **Contextual Continuity:** ADRs often highlight areas where technical debt was incurred due to architectural choices. TDRs extend this by documenting the debt's specifics and its implications. 78 | - **Decision Impact Analysis:** By maintaining TDRs alongside ADRs, teams can assess how past decisions continue to affect the project and address any resulting technical debt. 79 | - **Holistic Documentation:** Together, ADRs and TDRs offer a comprehensive view of both the strategic decisions and their technical repercussions, enabling better governance and continuous improvement. 80 | 81 | ## Using the TDR Generator Program 82 | 83 | This Go-based tool facilitates the creation of TDRs in multiple formats. Below is a guide on how to set up and use the program effectively. 84 | 85 | ### Prerequisites 86 | 87 | - **Go Programming Language:** Ensure that Go is installed on your machine. You can download it from the [official website](https://golang.org/dl/). 88 | - **Git (Optional):** For version control and integration purposes. 89 | 90 | ### Installation 91 | 92 | ```bash 93 | go install github.com/ms1963/TechnicalDebtRecords/src@latest 94 | ``` 95 | -------------------------------------------------------------------------------- /src/generate-td_test.go: -------------------------------------------------------------------------------- 1 | // generate-td_test.go 2 | package main 3 | 4 | import ( 5 | "os" 6 | "strings" 7 | "testing" 8 | ) 9 | 10 | // TestValidateTechnicalDebt checks the validation of the TechnicalDebt structure 11 | func TestValidateTechnicalDebt(t *testing.T) { 12 | tests := []struct { 13 | name string 14 | td TechnicalDebt 15 | wantErr bool 16 | }{ 17 | { 18 | name: "Valid TechnicalDebt", 19 | td: TechnicalDebt{ 20 | Title: "Outdated Library", 21 | Author: "Jane Doe", 22 | Version: "1.0.0", 23 | Date: "2024-04-15", 24 | State: "Analyzed", 25 | }, 26 | wantErr: false, 27 | }, 28 | { 29 | name: "Missing Title", 30 | td: TechnicalDebt{ 31 | Author: "Jane Doe", 32 | Version: "1.0.0", 33 | Date: "2024-04-15", 34 | State: "Analyzed", 35 | }, 36 | wantErr: true, 37 | }, 38 | { 39 | name: "Missing Author", 40 | td: TechnicalDebt{ 41 | Title: "Outdated Library", 42 | Version: "1.0.0", 43 | Date: "2024-04-15", 44 | State: "Analyzed", 45 | }, 46 | wantErr: true, 47 | }, 48 | { 49 | name: "Missing Version", 50 | td: TechnicalDebt{ 51 | Title: "Outdated Library", 52 | Author: "Jane Doe", 53 | Date: "2024-04-15", 54 | State: "Analyzed", 55 | }, 56 | wantErr: true, 57 | }, 58 | { 59 | name: "Missing Date", 60 | td: TechnicalDebt{ 61 | Title: "Outdated Library", 62 | Author: "Jane Doe", 63 | Version: "1.0.0", 64 | State: "Analyzed", 65 | }, 66 | wantErr: true, 67 | }, 68 | { 69 | name: "Missing State", 70 | td: TechnicalDebt{ 71 | Title: "Outdated Library", 72 | Author: "Jane Doe", 73 | Version: "1.0.0", 74 | Date: "2024-04-15", 75 | }, 76 | wantErr: true, 77 | }, 78 | } 79 | 80 | for _, tt := range tests { 81 | t.Run(tt.name, func(t *testing.T) { 82 | if err := validateTechnicalDebt(tt.td); (err != nil) != tt.wantErr { 83 | t.Errorf("validateTechnicalDebt() error = %v, wantErr %v", err, tt.wantErr) 84 | } 85 | }) 86 | } 87 | } 88 | 89 | // TestGenerateMarkdown checks the generation of Markdown content 90 | func TestGenerateMarkdown(t *testing.T) { 91 | td := TechnicalDebt{ 92 | Title: "Outdated Library", 93 | Author: "Jane Doe", 94 | Version: "1.0.0", 95 | Date: "2024-04-15", 96 | State: "Analyzed", 97 | Relations: []string{"TDR-102", "TDR-103"}, 98 | Summary: "The library is outdated and causes security vulnerabilities.", 99 | Context: "Originally chosen for quick implementation.", 100 | ImpactTech: "Security risks and maintainability issues.", 101 | ImpactBus: "Impact on customer satisfaction.", 102 | Symptoms: "Error messages related to security protocols.", 103 | Severity: "High", 104 | PotentialRisks: "Data breaches and legal consequences.", 105 | ProposedSol: "Library replacement and implementation of 2FA.", 106 | CostDelay: "Increased risk of security breaches.", 107 | Effort: "4 weeks and €10,000.", 108 | Dependencies: "Completion of the security audit.", 109 | Additional: "Training for the development team.", 110 | } 111 | 112 | expected := `# Technical Debt Record 113 | 114 | ## Title 115 | 116 | **Outdated Library** 117 | 118 | ## Author 119 | 120 | Jane Doe 121 | 122 | ## Version 123 | 124 | 1.0.0 125 | 126 | ## Date 127 | 128 | 2024-04-15 129 | 130 | ## State 131 | 132 | Analyzed 133 | 134 | ## Relations 135 | 136 | - [TDR-102](#) 137 | - [TDR-103](#) 138 | 139 | ## Summary 140 | 141 | The library is outdated and causes security vulnerabilities. 142 | 143 | ## Context 144 | 145 | Originally chosen for quick implementation. 146 | 147 | ## Impact 148 | 149 | ### Technical Impact 150 | 151 | Security risks and maintainability issues. 152 | 153 | ### Business Impact 154 | 155 | Impact on customer satisfaction. 156 | 157 | ## Symptoms 158 | 159 | Error messages related to security protocols. 160 | 161 | ## Severity 162 | 163 | High 164 | 165 | ## Potential Risks 166 | 167 | Data breaches and legal consequences. 168 | 169 | ## Proposed Solution 170 | 171 | Library replacement and implementation of 2FA. 172 | 173 | ## Cost of Delay 174 | 175 | Increased risk of security breaches. 176 | 177 | ## Effort to Resolve 178 | 179 | 4 weeks and €10,000. 180 | 181 | ## Dependencies 182 | 183 | Completion of the security audit. 184 | 185 | ## Additional Notes 186 | 187 | Training for the development team. 188 | ` 189 | 190 | result := generateMarkdown(td) 191 | if strings.TrimSpace(result) != strings.TrimSpace(expected) { 192 | t.Errorf("generateMarkdown() = \n%s\n, want \n%s", result, expected) 193 | } 194 | } 195 | 196 | // Example excerpt from generate-td_test.go 197 | 198 | func TestGenerateASCII(t *testing.T) { 199 | td := TechnicalDebt{ 200 | Title: "Outdated Library", 201 | Author: "Jane Doe", 202 | Version: "1.0.0", 203 | Date: "2024-04-15", 204 | State: "Analyzed", 205 | Relations: []string{"TDR-102", "TDR-103"}, 206 | Summary: "The library is outdated and causes security vulnerabilities.", 207 | Context: "Originally chosen for quick implementation.", 208 | ImpactTech: "Security risks and maintainability issues.", 209 | ImpactBus: "Impact on customer satisfaction.", 210 | Symptoms: "Error messages related to security protocols.", 211 | Severity: "High", 212 | PotentialRisks: "Data breaches and legal consequences.", 213 | ProposedSol: "Library replacement and implementation of 2FA.", 214 | CostDelay: "Increased risk of security breaches.", 215 | Effort: "4 weeks and €10,000.", 216 | Dependencies: "Completion of the security audit.", 217 | Additional: "Training for the development team.", 218 | } 219 | 220 | expected := `Technical Debt Record 221 | ==================== 222 | 223 | Title: 224 | ------ 225 | Outdated Library 226 | 227 | Author: 228 | ------- 229 | Jane Doe 230 | 231 | Version: 232 | -------- 233 | 1.0.0 234 | 235 | Date: 236 | ----- 237 | 2024-04-15 238 | 239 | State: 240 | ------ 241 | Analyzed 242 | 243 | Relations: 244 | ---------- 245 | - TDR-102 246 | - TDR-103 247 | 248 | Summary: 249 | -------- 250 | The library is outdated and causes security vulnerabilities. 251 | 252 | Context: 253 | -------- 254 | Originally chosen for quick implementation. 255 | 256 | Impact: 257 | ------- 258 | Technical Impact: 259 | - Security risks and maintainability issues. 260 | 261 | Business Impact: 262 | - Impact on customer satisfaction. 263 | 264 | Symptoms: 265 | --------- 266 | Error messages related to security protocols. 267 | 268 | Severity: 269 | --------- 270 | High 271 | 272 | Potential Risks: 273 | ---------------- 274 | Data breaches and legal consequences. 275 | 276 | Proposed Solution: 277 | ------------------- 278 | Library replacement and implementation of 2FA. 279 | 280 | Cost of Delay: 281 | --------------- 282 | Increased risk of security breaches. 283 | 284 | Effort to Resolve: 285 | ------------------- 286 | 4 weeks and €10,000. 287 | 288 | Dependencies: 289 | ------------- 290 | Completion of the security audit. 291 | 292 | Additional Notes: 293 | ----------------- 294 | Training for the development team. 295 | ` 296 | 297 | result := generateASCII(td) 298 | if strings.TrimSpace(result) != strings.TrimSpace(expected) { 299 | t.Errorf("generateASCII() = \n%s\n, want \n%s", result, expected) 300 | } 301 | } 302 | 303 | // TestGeneratePDF checks the generation of a PDF file (basic existence check) 304 | func TestGeneratePDF(t *testing.T) { 305 | td := TechnicalDebt{ 306 | Title: "Outdated Library", 307 | Author: "Jane Doe", 308 | Version: "1.0.0", 309 | Date: "2024-04-15", 310 | State: "Analyzed", 311 | Relations: []string{"TDR-102", "TDR-103"}, 312 | Summary: "The library is outdated and causes security vulnerabilities.", 313 | Context: "Originally chosen for quick implementation.", 314 | ImpactTech: "Security risks and maintainability issues.", 315 | ImpactBus: "Impact on customer satisfaction.", 316 | Symptoms: "Error messages related to security protocols.", 317 | Severity: "High", 318 | PotentialRisks: "Data breaches and legal consequences.", 319 | ProposedSol: "Library replacement and implementation of 2FA.", 320 | CostDelay: "Increased risk of security breaches.", 321 | Effort: "4 weeks and €10,000.", 322 | Dependencies: "Completion of the security audit.", 323 | Additional: "Training for the development team.", 324 | } 325 | 326 | filename := "test_output.pdf" 327 | 328 | // Generate PDF 329 | err := generatePDF(td, filename) 330 | if err != nil { 331 | t.Fatalf("generatePDF() failed: %v", err) 332 | } 333 | 334 | // Check if the file exists 335 | if _, err := os.Stat(filename); os.IsNotExist(err) { 336 | t.Errorf("generatePDF() failed to create the file: %s", filename) 337 | } 338 | 339 | // Clean up 340 | os.Remove(filename) 341 | } 342 | 343 | // TestGenerateExcel checks the generation of an Excel file (basic existence check) 344 | func TestGenerateExcel(t *testing.T) { 345 | td := TechnicalDebt{ 346 | Title: "Outdated Library", 347 | Author: "Jane Doe", 348 | Version: "1.0.0", 349 | Date: "2024-04-15", 350 | State: "Analyzed", 351 | Relations: []string{"TDR-102", "TDR-103"}, 352 | Summary: "The library is outdated and causes security vulnerabilities.", 353 | Context: "Originally chosen for quick implementation.", 354 | ImpactTech: "Security risks and maintainability issues.", 355 | ImpactBus: "Impact on customer satisfaction.", 356 | Symptoms: "Error messages related to security protocols.", 357 | Severity: "High", 358 | PotentialRisks: "Data breaches and legal consequences.", 359 | ProposedSol: "Library replacement and implementation of 2FA.", 360 | CostDelay: "Increased risk of security breaches.", 361 | Effort: "4 weeks and €10,000.", 362 | Dependencies: "Completion of the security audit.", 363 | Additional: "Training for the development team.", 364 | } 365 | 366 | filename := "test_output.xlsx" 367 | 368 | // Generate Excel 369 | err := generateExcel(td, filename) 370 | if err != nil { 371 | t.Fatalf("generateExcel() failed: %v", err) 372 | } 373 | 374 | // Check if the file exists 375 | if _, err := os.Stat(filename); os.IsNotExist(err) { 376 | t.Errorf("generateExcel() failed to create the file: %s", filename) 377 | } 378 | 379 | // Clean up 380 | os.Remove(filename) 381 | } 382 | -------------------------------------------------------------------------------- /docs/article_german.md: -------------------------------------------------------------------------------- 1 | # Technical Debt Records (TDRs) und das Werkzeug zu ihrer Erstellung 2 | 3 | ## Einleitung 4 | 5 | In der heutigen schnelllebigen Softwareentwicklung stehen Teams vor der Herausforderung, kontinuierlich neue Funktionen bereitzustellen und gleichzeitig die Codequalität zu erhalten. Dabei entstehen oft Kompromisse, die als **Technical Debt** (Technische Schulden) bezeichnet werden. Um diese systematisch zu dokumentieren und zu verwalten, haben sich **Technical Debt Records (TDRs)** etabliert. In diesem Artikel erläutern wir die Bedeutung von TDRs, wie sie Entwicklern, Architekten und Testern helfen, und stellen ein Werkzeug vor, das die Erstellung von TDRs vereinfacht. 6 | 7 | ## Was sind Technical Debt Records (TDRs)? 8 | 9 | Ein **Technical Debt Record (TDR)** ist ein strukturiertes Dokument, das Details über technische Schulden in einem Softwareprojekt festhält. Technische Schulden entstehen, wenn kurzfristige Lösungen gewählt werden, die zwar schnell implementiert werden können, aber langfristig zu erhöhtem Wartungsaufwand, schlechterer Performance oder anderen Nachteilen führen. TDRs bieten eine klare Übersicht über bestehende technische Schulden, deren Auswirkungen und die Maßnahmen zu ihrer Behebung. 10 | 11 | ## Motivation für TDRs 12 | 13 | Technische Schulden können, wenn sie unkontrolliert bleiben, erhebliche negative Auswirkungen auf ein Projekt haben: 14 | 15 | - **Codequalität:** Erhöhter Wartungsaufwand und sinkende Codequalität. 16 | - **Skalierbarkeit:** Schwierigkeiten bei der Erweiterung und Anpassung der Software. 17 | - **Performance:** Mögliche Leistungseinbußen durch suboptimale Implementierungen. 18 | - **Risikomanagement:** Erhöhtes Risiko von Systemausfällen oder Sicherheitslücken. 19 | 20 | Durch die systematische Dokumentation mittels TDRs können Teams diese Schulden frühzeitig erkennen, priorisieren und gezielt angehen, bevor sie unkontrollierbar werden. 21 | 22 | ## Vorteile von TDRs für Entwickler, Architekten und Tester 23 | 24 | ### Für Entwickler 25 | 26 | - **Transparenz:** Klare Dokumentation der bestehenden technischen Schulden erleichtert das Verständnis der Codebasis. 27 | - **Priorisierung:** Ermöglicht die Fokussierung auf kritische Bereiche, die sofortige Aufmerksamkeit erfordern. 28 | - **Wiederverwendbarkeit:** Vermeidung von doppeltem Aufwand durch das Bewusstsein über bereits bekannte Probleme. 29 | 30 | ### Für Architekten 31 | 32 | - **Strategische Planung:** Unterstützung bei der Planung von Refactoring-Maßnahmen und Architekturverbesserungen. 33 | - **Risikobewertung:** Einschätzung der Auswirkungen technischer Schulden auf die Gesamtarchitektur. 34 | - **Entscheidungsgrundlage:** Datenbasierte Entscheidungen zur Weiterentwicklung der Systemarchitektur. 35 | 36 | ### Für Tester 37 | 38 | - **Fokus auf kritische Bereiche:** Kenntnis über problematische Bereiche ermöglicht gezieltere Tests und höhere Testabdeckung. 39 | - **Verbesserte Teststrategien:** Anpassung der Testpläne basierend auf den identifizierten technischen Schulden. 40 | - **Qualitätssicherung:** Sicherstellung, dass behobene Schulden die gewünschte Qualitätssteigerung bringen. 41 | 42 | ## Das TDR-Template und seine Felder 43 | 44 | Ein gut strukturiertes TDR-Template ist entscheidend für die effektive Dokumentation technischer Schulden. Unser Werkzeug generiert TDRs mit folgenden Feldern: 45 | 46 | 1. **Titel:** Eine prägnante Bezeichnung der technischen Schuld. 47 | 2. **Autor:** Die Person, die die Schuld identifiziert oder dokumentiert hat. 48 | 3. **Version:** Die Version des Projekts oder der Komponente, in der die Schuld existiert. 49 | 4. **Datum:** Das Datum der Identifikation oder Dokumentation der Schuld. 50 | 5. **State:** Der aktuelle Status der technischen Schuld (z.B. Identified, Analyzed, Approved, In Progress, Resolved, Closed, Rejected). 51 | 6. **Relations:** Verweise auf andere verwandte TDRs, um Zusammenhänge zu verdeutlichen. 52 | 7. **Zusammenfassung:** Eine kurze Übersicht über die technische Schuld und deren Bedeutung. 53 | 8. **Kontext:** Detaillierte Hintergrundinformationen, warum die Schuld entstanden ist (z.B. Zeitdruck, veraltete Technologien). 54 | 9. **Auswirkungen:** 55 | - **Technische Auswirkungen:** Wie die Schuld die Systemleistung, Skalierbarkeit oder Wartbarkeit beeinflusst. 56 | - **Geschäftliche Auswirkungen:** Die Auswirkungen auf Geschäftsprozesse, Kundenzufriedenheit oder Risikoebenen. 57 | 10. **Symptome:** Beobachtbare Anzeichen, die auf die Präsenz der technischen Schuld hinweisen (z.B. häufige Bugs, langsame Performance). 58 | 11. **Schweregrad:** Die Kritikalität der Schuld (Critical, High, Medium, Low). 59 | 12. **Potenzielle Risiken:** Mögliche negative Folgen, wenn die Schuld nicht behoben wird (z.B. Sicherheitslücken, erhöhte Kosten). 60 | 13. **Vorgeschlagene Lösung:** Empfohlene Maßnahmen zur Behebung der technischen Schuld. 61 | 14. **Kosten der Verzögerung:** Die Konsequenzen, wenn die Behebung der Schuld verzögert wird. 62 | 15. **Aufwand zur Behebung:** Geschätzter Aufwand in Zeit und Ressourcen, um die Schuld zu beheben. 63 | 16. **Abhängigkeiten:** Andere Aufgaben, Komponenten oder externe Faktoren, die die Behebung der Schuld beeinflussen. 64 | 17. **Zusätzliche Hinweise:** Weitere relevante Informationen oder Überlegungen zur Schuld. 65 | 66 | ### Rationale für das `State`-Feld 67 | 68 | Das `State`-Feld spiegelt den Workflow wider, wie technische Schulden gehandhabt werden. Es hilft dabei, den Fortschritt bei der Bearbeitung der Schuld zu verfolgen und sicherzustellen, dass keine Schulden unbeachtet bleiben. Die definierten Zustände sind: 69 | 70 | - **Identified:** Die technische Schuld wurde erkannt. 71 | - **Analyzed:** Die Auswirkungen und der Aufwand zur Behebung wurden bewertet. 72 | - **Approved:** Die Behebung der Schuld wurde genehmigt. 73 | - **In Progress:** Die Arbeit zur Behebung der Schuld ist im Gange. 74 | - **Resolved:** Die technische Schuld wurde behoben. 75 | - **Closed:** Der TDR wurde abgeschlossen und ist nicht mehr relevant. 76 | - **Rejected:** Die Behebung der Schuld wurde abgelehnt. 77 | 78 | Diese Zustände ermöglichen es Teams, den Status jeder technischen Schuld klar zu definieren und entsprechende Maßnahmen zu ergreifen. 79 | 80 | ### Anpassung der Felder je nach State 81 | 82 | Beim ersten Identifizieren einer technischen Schuld können einige Felder noch leer bleiben: 83 | 84 | - **Initiale Identifikation (`Identified`):** 85 | - **Gefüllt:** Titel, Autor, Version, Datum, State, Zusammenfassung, Kontext. 86 | - **Leer:** Auswirkungen, Symptome, Schweregrad, Potenzielle Risiken, Vorgeschlagene Lösung, Kosten der Verzögerung, Aufwand zur Behebung, Abhängigkeiten, Zusätzliche Hinweise. 87 | 88 | - **Analysephase (`Analyzed`):** 89 | - **Gefüllt:** Alle Felder des `Identified`-Status plus Auswirkungen, Symptome, Schweregrad, Potenzielle Risiken. 90 | 91 | - **Genehmigungsphase (`Approved`):** 92 | - **Gefüllt:** Alle bisherigen Felder plus Vorgeschlagene Lösung, Kosten der Verzögerung. 93 | 94 | - **Umsetzungsphase (`In Progress`):** 95 | - **Gefüllt:** Alle bisherigen Felder plus Aufwand zur Behebung, Abhängigkeiten. 96 | 97 | - **Abschlussphase (`Resolved` & `Closed`):** 98 | - **Gefüllt:** Alle Felder einschließlich Zusätzliche Hinweise. 99 | 100 | Durch diese schrittweise Ergänzung bleibt die Dokumentation stets aktuell und reflektiert den Fortschritt bei der Behebung der technischen Schulden. 101 | 102 | ## Das Werkzeug zur Erstellung von TDRs 103 | 104 | Unser **TDR-Generator** ist ein Go-basiertes Tool, das die Erstellung von Technical Debt Records in verschiedenen Formaten automatisiert. Es unterstützt **Markdown**, **Plain ASCII**, **PDF** und **Excel** und erleichtert somit die Integration in unterschiedliche Entwicklungs- und Dokumentationsprozesse. 105 | 106 | ### Features des TDR-Generators 107 | 108 | - **Benutzerfreundlich:** Interaktive Eingabeaufforderungen führen den Benutzer durch das Ausfüllen der TDR-Felder. 109 | - **Flexibel:** Unterstützung mehrerer Ausgabeformate zur Anpassung an verschiedene Anforderungen. 110 | - **Automatische Validierung:** Überprüfung der Eingaben auf Vollständigkeit und Korrektheit. 111 | - **Version Control Integration:** Leichtes Einchecken der generierten TDRs in Systeme wie Git oder SVN. 112 | 113 | ### Repository und Installation 114 | 115 | Der TDR-Generator ist auf GitHub verfügbar. Sie können das Repository [hier](https://github.com/ms1963/TechnicalDebtRecords) finden. 116 | 117 | #### Schritte zur Installation: 118 | 119 | 1. **Clone das Repository:** 120 | 121 | ```bash 122 | git clone https://github.com/ms1963/TechnicalDebtRecords.git 123 | ``` 124 | 125 | 2. **Initialisiere das Go-Modul:** 126 | 127 | ```bash 128 | go mod init technical_debt_generator 129 | ``` 130 | 131 | 3. **Installiere die Abhängigkeiten:** 132 | 133 | ```bash 134 | go get github.com/phpdave11/gofpdf 135 | go get github.com/xuri/excelize/v2 136 | ``` 137 | 138 | 4. **Build das Programm:** 139 | 140 | ```bash 141 | go build generate-td.go 142 | ``` 143 | 144 | ### Nutzung des TDR-Generators 145 | 146 | Das Programm kann über die Kommandozeile mit verschiedenen Optionen ausgeführt werden. 147 | 148 | #### Verfügbare Optionen: 149 | 150 | - `-format`: Gibt das Ausgabeformat an. Mögliche Werte sind `markdown`, `ascii`, `pdf`, `excel`. Standard ist `markdown`. 151 | - `-output`: (Optional) Gibt den Dateinamen für die Ausgabe an. Wenn nicht angegeben, wird ein Standardname verwendet. 152 | - `-empty`: (Optional) Erstellt ein leeres TDR mit Platzhaltern, ohne nach Eingaben zu fragen. 153 | - `--help` oder `-h`: Zeigt die Hilfsnachricht mit Nutzungshinweisen an. 154 | 155 | #### Beispiele: 156 | 157 | 1. **Generiere ein Markdown-TDR:** 158 | 159 | ```bash 160 | ./generate_td -format markdown 161 | ``` 162 | 163 | 2. **Generiere ein PDF-TDR mit benutzerdefiniertem Dateinamen:** 164 | 165 | ```bash 166 | ./generate_td -format pdf -output mein_td_record.pdf 167 | ``` 168 | 169 | 3. **Generiere ein leeres Excel-TDR:** 170 | 171 | ```bash 172 | ./generate_td -format excel -empty 173 | ``` 174 | 175 | 4. **Zeige die Hilfemeldung an:** 176 | 177 | ```bash 178 | ./generate_td --help 179 | ``` 180 | 181 | ### Integration in Versionskontrollsysteme 182 | 183 | Um die Nachverfolgung und Zusammenarbeit zu erleichtern, sollten TDRs in ein Versionskontrollsystem wie **Git** oder **SVN** eingecheckt werden. Dies ermöglicht: 184 | 185 | - **Versionierung:** Nachverfolgung von Änderungen und Historie der technischen Schulden. 186 | - **Zusammenarbeit:** Gemeinsame Bearbeitung und Überprüfung von TDRs durch das Team. 187 | - **Zugänglichkeit:** Einfache Integration in bestehende Entwicklungsprozesse und Pipelines. 188 | 189 | #### Beispiel für Git: 190 | 191 | 1. **Füge das TDR dem Repository hinzu:** 192 | 193 | ```bash 194 | git add technical_debt_record.md 195 | ``` 196 | 197 | 2. **Commite die Änderung:** 198 | 199 | ```bash 200 | git commit -m "Add TDR für veraltete Authentifizierungsbibliothek" 201 | ``` 202 | 203 | 3. **Übertrage die Änderung ins Repository:** 204 | 205 | ```bash 206 | git push origin main 207 | ``` 208 | 209 | Durch die Einbindung von TDRs in das Versionskontrollsystem bleibt die Dokumentation stets aktuell und für alle Teammitglieder zugänglich. 210 | 211 | ## Fazit 212 | 213 | **Technical Debt Records (TDRs)** sind ein unverzichtbares Instrument zur Verwaltung technischer Schulden in Softwareprojekten. Sie bieten Transparenz, erleichtern die Priorisierung und unterstützen strategische Entscheidungen zur Verbesserung der Codequalität und Systemarchitektur. Der vorgestellte **TDR-Generator** vereinfacht die Erstellung dieser wichtigen Dokumente und integriert sich nahtlos in bestehende Entwicklungs- und Versionskontrollprozesse. 214 | 215 | Indem Teams TDRs konsequent verwenden und in ihre Workflows integrieren, können sie die negativen Auswirkungen technischer Schulden minimieren und die langfristige Gesundheit und Wartbarkeit ihrer Softwareprojekte sicherstellen. 216 | 217 | 218 | -------------------------------------------------------------------------------- /docs/article.md: -------------------------------------------------------------------------------- 1 | # Technical Debt Records (TDRs) and the Tool to Create Them 2 | 3 | ## Introduction 4 | 5 | In today's fast-paced software development landscape, teams face the challenge of continuously delivering new features while maintaining code quality. This often leads to compromises known as **Technical Debt**. To systematically document and manage this debt, **Technical Debt Records (TDRs)** have emerged as a vital tool. This article explores the significance of TDRs, how they benefit developers, architects, and testers, and introduces a tool that simplifies the creation of TDRs. 6 | 7 | ## What are Technical Debt Records (TDRs)? 8 | 9 | A **Technical Debt Record (TDR)** is a structured document that captures details about technical debt within a software project. Technical debt arises when short-term solutions are chosen for immediate gains, leading to increased maintenance costs, reduced performance, or other long-term disadvantages. TDRs provide a clear overview of existing technical debt, its impacts, and the measures needed to address it. 10 | 11 | ## Motivation for TDRs 12 | 13 | Unmanaged technical debt can accumulate over time, resulting in significant negative consequences: 14 | 15 | - **Code Quality:** Increased maintenance efforts and declining code quality. 16 | - **Scalability:** Challenges in scaling and adapting the software. 17 | - **Performance:** Potential performance degradation due to suboptimal implementations. 18 | - **Risk Management:** Elevated risks of system failures or security vulnerabilities. 19 | 20 | By systematically documenting technical debt through TDRs, teams can proactively identify, prioritize, and address these issues before they become unmanageable. 21 | 22 | ## Benefits of TDRs for Developers, Architects, and Testers 23 | 24 | ### For Developers 25 | 26 | - **Transparency:** Clear documentation of existing technical debt enhances understanding of the codebase. 27 | - **Prioritization:** Helps focus on critical areas that require immediate attention. 28 | - **Reusability:** Awareness of known issues prevents duplicate efforts in troubleshooting and fixing problems. 29 | 30 | ### For Architects 31 | 32 | - **Strategic Planning:** Assists in planning refactoring efforts and architectural improvements. 33 | - **Risk Assessment:** Evaluates the impact of technical debt on the overall system architecture. 34 | - **Decision-Making:** Provides data-driven insights for making informed decisions about system evolution. 35 | 36 | ### For Testers 37 | 38 | - **Focused Testing:** Knowledge of problematic areas allows for more targeted and effective testing strategies. 39 | - **Enhanced Test Coverage:** Ensures that areas affected by technical debt receive adequate testing attention. 40 | - **Quality Assurance:** Guarantees that resolved debts contribute to overall software quality improvements. 41 | 42 | ## The TDR Template and Its Fields 43 | 44 | A well-structured TDR template is crucial for effective documentation of technical debt. The tool we present generates TDRs with the following fields: 45 | 46 | 1. **Title:** A concise name for the technical debt. 47 | 2. **Author:** The individual who identified or is documenting the debt. 48 | 3. **Version:** The version of the project or component where the debt exists. 49 | 4. **Date:** The date when the debt was identified or recorded. 50 | 5. **State:** The current workflow stage of the technical debt (e.g., Identified, Analyzed, Approved, In Progress, Resolved, Closed, Rejected). 51 | 6. **Relations:** Links to other related TDRs to establish connections between different debt items. 52 | 7. **Summary:** A brief overview explaining the nature and significance of the technical debt. 53 | 8. **Context:** Detailed background information, including why the debt was incurred (e.g., time constraints, outdated technologies). 54 | 9. **Impact:** 55 | - **Technical Impact:** How the debt affects system performance, scalability, maintainability, etc. 56 | - **Business Impact:** The repercussions on business operations, customer satisfaction, risk levels, etc. 57 | 10. **Symptoms:** Observable signs indicating the presence of technical debt (e.g., frequent bugs, slow performance). 58 | 11. **Severity:** The criticality level of the debt (Critical, High, Medium, Low). 59 | 12. **Potential Risks:** Possible adverse outcomes if the debt remains unaddressed (e.g., security vulnerabilities, increased costs). 60 | 13. **Proposed Solution:** Recommended actions or strategies to resolve the debt. 61 | 14. **Cost of Delay:** Consequences of postponing the resolution of the debt. 62 | 15. **Effort to Resolve:** Estimated resources, time, and effort required to address the debt. 63 | 16. **Dependencies:** Other tasks, components, or external factors that the resolution of the debt depends on. 64 | 17. **Additional Notes:** Any other relevant information or considerations related to the debt. 65 | 66 | ### Rationale for the `State` Field 67 | 68 | The `State` field reflects the workflow stages of handling technical debt. It helps track the progress of each debt item and ensures that no debts remain unattended. The defined states are: 69 | 70 | - **Identified:** The technical debt has been recognized. 71 | - **Analyzed:** The impact and effort required to address the debt have been assessed. 72 | - **Approved:** The resolution of the technical debt has been approved. 73 | - **In Progress:** Work to resolve the technical debt is underway. 74 | - **Resolved:** The technical debt has been addressed. 75 | - **Closed:** The technical debt record is closed. 76 | - **Rejected:** The resolution of the technical debt has been rejected. 77 | 78 | ### Adjusting Fields Based on State 79 | 80 | When initially identifying a technical debt, some fields may remain empty and be filled out as the debt progresses through different states: 81 | 82 | - **Initial Identification (`Identified`):** 83 | - **Filled:** Title, Author, Version, Date, State, Summary, Context. 84 | - **Empty:** Impact, Symptoms, Severity, Potential Risks, Proposed Solution, Cost of Delay, Effort to Resolve, Dependencies, Additional Notes. 85 | 86 | - **Analysis Phase (`Analyzed`):** 87 | - **Filled:** All fields from `Identified` plus Impact, Symptoms, Severity, Potential Risks. 88 | 89 | - **Approval Phase (`Approved`):** 90 | - **Filled:** All previous fields plus Proposed Solution, Cost of Delay. 91 | 92 | - **Implementation Phase (`In Progress`):** 93 | - **Filled:** All previous fields plus Effort to Resolve, Dependencies. 94 | 95 | - **Completion Phase (`Resolved` & `Closed`):** 96 | - **Filled:** All fields including Additional Notes. 97 | 98 | This phased approach ensures that TDRs remain up-to-date and accurately reflect the current status of each technical debt item. 99 | 100 | ## The Tool to Create TDRs 101 | 102 | Our **TDR Generator** is a Go-based tool that automates the creation of Technical Debt Records in multiple formats. It supports **Markdown**, **Plain ASCII**, **PDF**, and **Excel**, facilitating integration into various development and documentation workflows. 103 | 104 | ### Features of the TDR Generator 105 | 106 | - **User-Friendly:** Interactive prompts guide users through filling out TDR fields. 107 | - **Flexible:** Supports multiple output formats to suit different documentation needs. 108 | - **Automatic Validation:** Ensures input completeness and correctness. 109 | - **Version Control Integration:** Easily check TDRs into systems like Git or SVN. 110 | 111 | ### Repository and Installation 112 | 113 | The TDR Generator is available on GitHub. You can access the repository [here](https://github.com/ms1963/TechnicalDebtRecords). 114 | 115 | #### Installation Steps: 116 | 117 | 1. **Clone the Repository:** 118 | 119 | ```bash 120 | git clone https://github.com/ms1963/TechnicalDebtRecords.git 121 | ``` 122 | 123 | 2. **Initialize the Go Module :** 124 | 125 | ```bash 126 | go mod init technical_debt_generator 127 | ``` 128 | 129 | 3. **Install Dependencies:** 130 | 131 | The program relies on two external libraries: 132 | 133 | - `gofpdf` for PDF generation. 134 | - `excelize` for Excel file creation. 135 | 136 | Install them using: 137 | 138 | ```bash 139 | go get github.com/phpdave11/gofpdf 140 | go get github.com/xuri/excelize/v2 141 | ``` 142 | 143 | 4. **Save the Program:** 144 | 145 | Create a file named `generate-td.go` and paste the complete program code provided above into it. 146 | 147 | ### Using the TDR Generator 148 | 149 | The program can be executed via the command line with various options to customize the output. 150 | 151 | #### Available Options: 152 | 153 | - `-format`: Specifies the output format. Supported formats are: 154 | - `markdown` (default) 155 | - `ascii` 156 | - `pdf` 157 | - `excel` 158 | 159 | **Example:** 160 | 161 | ```bash 162 | ./generate_td -format pdf 163 | ``` 164 | 165 | - `-output`: (Optional) Specifies the output filename. If not provided, a default filename with the appropriate extension is generated based on the selected format. 166 | 167 | **Example:** 168 | 169 | ```bash 170 | ./generate_td -format markdown -output my_debt_record.md 171 | ``` 172 | 173 | - `-empty`: (Optional) If set, the program generates an empty TDR template with placeholders without prompting for input. 174 | 175 | **Example:** 176 | 177 | ```bash 178 | ./generate_td -format excel -empty 179 | ``` 180 | 181 | - `--help` or `-h`: Displays a help message with usage instructions. 182 | 183 | **Example:** 184 | 185 | ```bash 186 | ./generate_td --help 187 | ``` 188 | 189 | #### Interactive Prompts: 190 | 191 | When generating a non-empty TDR, the program will interactively prompt you to enter values for each field, including the new `State` field. 192 | 193 | **Sample Interaction:** 194 | 195 | ```bash 196 | ./generate_td -format markdown 197 | ``` 198 | 199 | ``` 200 | Enter the Title of the Technical Debt: Outdated Authentication Library 201 | Enter the Author of the Document: Jane Doe 202 | Enter the Version (e.g., 1.0.0): 1.2.3 203 | Enter the Date (YYYY-MM-DD) [Leave blank for today]: 204 | 205 | Select the State of the Technical Debt: 206 | 1) Identified 207 | 2) Analyzed 208 | 3) Approved 209 | 4) In Progress 210 | 5) Resolved 211 | 6) Closed 212 | 7) Rejected 213 | Enter the number corresponding to the state: 2 214 | 215 | Enter related Technical Debt IDs (leave blank to finish): 216 | - Related TD ID: TD-101 217 | - Related TD ID: TD-202 218 | - Related TD ID: 219 | 220 | Enter Summary: The current authentication library is outdated and poses security risks. 221 | Enter Context: Selected early to meet project deadlines, now incompatible with new security standards. 222 | Enter Technical Impact: Incompatibility with the latest framework version. 223 | Enter Business Impact: Increased risk of security breaches affecting customer trust. 224 | Enter Symptoms: Frequent security audit failures and increased bug reports. 225 | Enter Severity (Critical / High / Medium / Low): High 226 | Enter Potential Risks: Data breaches, legal liabilities, and loss of customer trust. 227 | Enter Proposed Solution: Replace the outdated library with a modern, well-supported alternative. 228 | Enter Cost of Delay: Each month of delay increases security vulnerabilities and complicates future upgrades. 229 | Enter Effort to Resolve: Approximately 6 weeks for two developers. 230 | Enter Dependencies: Completion of the ongoing security audit. 231 | Enter Additional Notes: Coordination with the operations team for seamless integration. 232 | 233 | Technical Debt record has been saved to 'technical_debt_record.md'. 234 | ``` 235 | 236 | #### Output Files: 237 | 238 | Depending on the selected format, the program generates the TDR in the specified format: 239 | 240 | - **Markdown (`.md`):** Structured and readable documentation suitable for version control and collaborative editing. 241 | - **Plain ASCII (`.txt`):** Simple text format for basic documentation needs. 242 | - **PDF (`.pdf`):** Portable Document Format for sharing and printing. 243 | - **Excel (`.xlsx`):** Spreadsheet format for data analysis and integration with other tools. 244 | 245 | ## Best Practices 246 | 247 | ### Version Control Integration 248 | 249 | **Technical Debt Records (TDRs)** are valuable documents that should be maintained alongside your codebase. To ensure that TDRs are effectively tracked and managed, consider the following best practices: 250 | 251 | 1. **Check TDRs into Version Control:** 252 | 253 | - **Git:** Commit TDRs to your Git repository alongside your code. This approach ensures that TDRs are versioned and can be reviewed, branched, and merged similarly to your source code. 254 | 255 | **Example:** 256 | ```bash 257 | git add technical_debt_record.md 258 | git commit -m "Add TDR for Outdated Authentication Library" 259 | git push origin main 260 | ``` 261 | 262 | - **SVN:** Similarly, commit TDRs to your SVN repository to maintain version history and collaboration. 263 | 264 | 2. **Organize TDRs:** 265 | 266 | - **Directory Structure:** Maintain a dedicated directory (e.g., `/docs/tdrs/`) within your repository to store all TDRs. This organization facilitates easy navigation and management. 267 | 268 | - **Naming Conventions:** Use clear and consistent naming conventions for TDR files, such as `TDR--.<extension>`. For example, `TDR-101-Outdated-Auth-Library.md`. 269 | 270 | 3. **Link TDRs with Issues or ADRs:** 271 | 272 | - **Issue Tracking Integration:** Reference TDRs in your issue tracker (e.g., Jira, GitHub Issues) to provide context and track resolution progress. 273 | 274 | - **Architecture Decision Records (ADRs):** Link related ADRs to TDRs to maintain a comprehensive documentation trail of architectural decisions and their technical debt implications. 275 | 276 | 4. **Regular Review and Updates:** 277 | 278 | - **Periodic Audits:** Schedule regular reviews of TDRs to assess their current state, prioritize resolutions, and update statuses as work progresses. 279 | 280 | - **Continuous Improvement:** Encourage team members to document new technical debt promptly and update existing TDRs to reflect any changes. 281 | 282 | 5. **Access Control:** 283 | 284 | - **Permissions:** Ensure that only authorized team members can create, modify, or delete TDRs to maintain data integrity and accountability. 285 | 286 | - **Collaboration:** Use version control features like pull requests or merge requests to facilitate collaborative reviews and approvals of TDRs. 287 | 288 | ## Conclusion 289 | 290 | **Technical Debt Records (TDRs)** are an indispensable tool for managing technical debt in software projects. They provide transparency, facilitate prioritization, and support strategic decisions to enhance code quality and system architecture. The introduced **TDR Generator** simplifies the creation of these essential documents and integrates seamlessly into existing development and version control workflows. 291 | 292 | By consistently utilizing TDRs and integrating them into your version control systems like Git or SVN, teams can effectively manage technical debt, ensuring the long-term health and maintainability of their software projects. 293 | 294 | -------------------------------------------------------------------------------- /src/generate-td.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "bufio" 5 | "errors" 6 | "flag" 7 | "fmt" 8 | "os" 9 | "path/filepath" 10 | "strconv" // Added strconv 11 | "strings" 12 | "time" 13 | 14 | "github.com/phpdave11/gofpdf" 15 | "github.com/xuri/excelize/v2" 16 | ) 17 | 18 | // TechnicalDebt represents a technical debt record 19 | type TechnicalDebt struct { 20 | Title string 21 | Author string 22 | Version string 23 | Date string 24 | State string 25 | Relations []string 26 | Summary string 27 | Context string 28 | ImpactTech string 29 | ImpactBus string 30 | Symptoms string 31 | Severity string 32 | PotentialRisks string 33 | ProposedSol string 34 | CostDelay string 35 | Effort string 36 | Dependencies string 37 | Additional string 38 | Empty bool 39 | } 40 | 41 | // AllowedStates defines the possible states of a Technical Debt Record 42 | var AllowedStates = []string{ 43 | "Identified", 44 | "Analyzed", 45 | "Approved", 46 | "In Progress", 47 | "Resolved", 48 | "Closed", 49 | "Rejected", 50 | } 51 | 52 | // validateTechnicalDebt ensures all required fields are present 53 | func validateTechnicalDebt(td TechnicalDebt) error { 54 | if td.Title == "" { 55 | return errors.New("Title is required") 56 | } 57 | if td.Author == "" { 58 | return errors.New("Author is required") 59 | } 60 | if td.Version == "" { 61 | return errors.New("Version is required") 62 | } 63 | if td.Date == "" { 64 | return errors.New("Date is required") 65 | } 66 | if td.State == "" { 67 | return errors.New("State is required") 68 | } 69 | return nil 70 | } 71 | 72 | // getInput prompts the user for input and returns the entered value 73 | func getInput(prompt string, required bool) (string, error) { 74 | reader := bufio.NewReader(os.Stdin) 75 | for { 76 | fmt.Print(prompt) 77 | input, err := reader.ReadString('\n') 78 | if err != nil { 79 | return "", err 80 | } 81 | input = strings.TrimSpace(input) 82 | if required && input == "" { 83 | fmt.Println("This field is required.") 84 | continue 85 | } 86 | return input, nil 87 | } 88 | } 89 | 90 | // getState prompts the user to select a state from the allowed states 91 | func getState() (string, error) { 92 | fmt.Println("Select the State of the Technical Debt:") 93 | for i, state := range AllowedStates { 94 | fmt.Printf(" %d) %s\n", i+1, state) 95 | } 96 | for { 97 | input, err := getInput("Enter the number corresponding to the state: ", true) 98 | if err != nil { 99 | return "", err 100 | } 101 | index, err := strconv.Atoi(input) // Use strconv to convert string to int 102 | if err != nil || index < 1 || index > len(AllowedStates) { 103 | fmt.Println("Invalid selection. Please enter a valid number.") 104 | continue 105 | } 106 | return AllowedStates[index-1], nil 107 | } 108 | } 109 | 110 | // getRelations prompts the user to enter related TDR IDs 111 | func getRelations() ([]string, error) { 112 | var relations []string 113 | fmt.Println("Enter related Technical Debt IDs (leave blank to finish):") 114 | for { 115 | rel, err := getInput(" - Related TD ID: ", false) 116 | if err != nil { 117 | return nil, err 118 | } 119 | if rel == "" { 120 | break 121 | } 122 | relations = append(relations, rel) 123 | } 124 | return relations, nil 125 | } 126 | 127 | // generateASCII generates the Plain ASCII content 128 | func generateASCII(td TechnicalDebt) string { 129 | relationsFormatted := "None" 130 | if len(td.Relations) > 0 { 131 | var rels []string 132 | for _, rel := range td.Relations { 133 | rels = append(rels, fmt.Sprintf("- %s", rel)) 134 | } 135 | relationsFormatted = strings.Join(rels, "\n") 136 | } 137 | 138 | if td.Empty { 139 | return fmt.Sprintf(`Technical Debt Record 140 | ==================== 141 | 142 | Title: 143 | ------ 144 | [Enter Title Here] 145 | 146 | Author: 147 | ------- 148 | [Enter Author Here] 149 | 150 | Version: 151 | -------- 152 | [Enter Version Here] 153 | 154 | Date: 155 | ----- 156 | [Enter Date Here] 157 | 158 | State: 159 | ------ 160 | [Enter State Here] 161 | 162 | Relations: 163 | ---------- 164 | %s 165 | 166 | Summary: 167 | -------- 168 | *A brief overview of the technical debt, explaining the problem in one or two sentences.* 169 | 170 | Context: 171 | -------- 172 | *Provide the historical context and reasons why this technical debt exists.* 173 | 174 | Impact: 175 | ------- 176 | Technical Impact: 177 | - *Describe the technical impact.* 178 | 179 | Business Impact: 180 | - *Describe the business impact.* 181 | 182 | Symptoms: 183 | --------- 184 | *List specific signs that indicate the presence of technical debt.* 185 | 186 | Severity: 187 | --------- 188 | *[Enter Severity Here: Critical / High / Medium / Low]* 189 | 190 | Potential Risks: 191 | ---------------- 192 | *Potential security vulnerabilities leading to data breaches.* 193 | 194 | Proposed Solution: 195 | ------------------- 196 | *Describe how to resolve the technical debt.* 197 | 198 | Cost of Delay: 199 | --------------- 200 | *Explain the consequences of delaying the resolution of the technical debt.* 201 | 202 | Effort to Resolve: 203 | ------------------- 204 | *Estimate the time, resources, and effort needed to address the debt.* 205 | 206 | Dependencies: 207 | ------------- 208 | *List any dependencies or blockers that need to be resolved before tackling the debt.* 209 | 210 | Additional Notes: 211 | ----------------- 212 | *Any other relevant information or considerations.* 213 | `, relationsFormatted) 214 | } 215 | 216 | // Normal ASCII generation 217 | return fmt.Sprintf(`Technical Debt Record 218 | ==================== 219 | 220 | Title: 221 | ------ 222 | %s 223 | 224 | Author: 225 | ------- 226 | %s 227 | 228 | Version: 229 | -------- 230 | %s 231 | 232 | Date: 233 | ----- 234 | %s 235 | 236 | State: 237 | ------ 238 | %s 239 | 240 | Relations: 241 | ---------- 242 | %s 243 | 244 | Summary: 245 | -------- 246 | %s 247 | 248 | Context: 249 | -------- 250 | %s 251 | 252 | Impact: 253 | ------- 254 | Technical Impact: 255 | - %s 256 | 257 | Business Impact: 258 | - %s 259 | 260 | Symptoms: 261 | --------- 262 | %s 263 | 264 | Severity: 265 | --------- 266 | %s 267 | 268 | Potential Risks: 269 | ---------------- 270 | %s 271 | 272 | Proposed Solution: 273 | ------------------- 274 | %s 275 | 276 | Cost of Delay: 277 | --------------- 278 | %s 279 | 280 | Effort to Resolve: 281 | ------------------- 282 | %s 283 | 284 | Dependencies: 285 | ------------- 286 | %s 287 | 288 | Additional Notes: 289 | ----------------- 290 | %s 291 | `, td.Title, td.Author, td.Version, td.Date, td.State, relationsFormatted, td.Summary, td.Context, 292 | td.ImpactTech, td.ImpactBus, td.Symptoms, td.Severity, td.PotentialRisks, td.ProposedSol, 293 | td.CostDelay, td.Effort, td.Dependencies, td.Additional) 294 | } 295 | 296 | // generateMarkdown generates the Markdown content 297 | func generateMarkdown(td TechnicalDebt) string { 298 | relationsFormatted := "None" 299 | if len(td.Relations) > 0 { 300 | var rels []string 301 | for _, rel := range td.Relations { 302 | rels = append(rels, fmt.Sprintf("- [%s](#)", rel)) 303 | } 304 | relationsFormatted = strings.Join(rels, "\n") 305 | } 306 | 307 | if td.Empty { 308 | return fmt.Sprintf(`# Technical Debt Record 309 | 310 | ## Title 311 | 312 | **[Enter Title Here]** 313 | 314 | ## Author 315 | 316 | [Enter Author Here] 317 | 318 | ## Version 319 | 320 | **[Enter Version Here]** 321 | 322 | ## Date 323 | 324 | [Enter Date Here] 325 | 326 | ## State 327 | 328 | [Enter State Here] 329 | 330 | ## Relations 331 | 332 | %s 333 | 334 | ## Summary 335 | 336 | *A brief overview of the technical debt, explaining the problem in one or two sentences.* 337 | 338 | ## Context 339 | 340 | *Provide the historical context and reasons why this technical debt exists.* 341 | 342 | ## Impact 343 | 344 | ### Technical Impact 345 | 346 | *Describe how the debt affects the system’s performance, scalability, or maintainability.* 347 | 348 | ### Business Impact 349 | 350 | *Explain how the debt affects the business, such as increased risk, customer dissatisfaction, or slower feature delivery.* 351 | 352 | ## Symptoms 353 | 354 | *List specific signs that indicate the presence of technical debt.* 355 | 356 | ## Severity 357 | 358 | *[Enter Severity Here: Critical / High / Medium / Low]* 359 | 360 | ## Potential Risks 361 | 362 | *Potential security vulnerabilities leading to data breaches.* 363 | 364 | ## Proposed Solution 365 | 366 | *Describe how to resolve the technical debt.* 367 | 368 | ## Cost of Delay 369 | 370 | *Explain the consequences of delaying the resolution of the technical debt.* 371 | 372 | ## Effort to Resolve 373 | 374 | *Estimate the time, resources, and effort needed to address the debt.* 375 | 376 | ## Dependencies 377 | 378 | *List any dependencies or blockers that need to be resolved before tackling the debt.* 379 | 380 | ## Additional Notes 381 | 382 | *Any other relevant information or considerations.* 383 | `, relationsFormatted) 384 | } 385 | 386 | // Normal Markdown generation 387 | return fmt.Sprintf(`# Technical Debt Record 388 | 389 | ## Title 390 | 391 | **%s** 392 | 393 | ## Author 394 | 395 | %s 396 | 397 | ## Version 398 | 399 | %s 400 | 401 | ## Date 402 | 403 | %s 404 | 405 | ## State 406 | 407 | %s 408 | 409 | ## Relations 410 | 411 | %s 412 | 413 | ## Summary 414 | 415 | %s 416 | 417 | ## Context 418 | 419 | %s 420 | 421 | ## Impact 422 | 423 | ### Technical Impact 424 | 425 | %s 426 | 427 | ### Business Impact 428 | 429 | %s 430 | 431 | ## Symptoms 432 | 433 | %s 434 | 435 | ## Severity 436 | 437 | %s 438 | 439 | ## Potential Risks 440 | 441 | %s 442 | 443 | ## Proposed Solution 444 | 445 | %s 446 | 447 | ## Cost of Delay 448 | 449 | %s 450 | 451 | ## Effort to Resolve 452 | 453 | %s 454 | 455 | ## Dependencies 456 | 457 | %s 458 | 459 | ## Additional Notes 460 | 461 | %s 462 | `, td.Title, td.Author, td.Version, td.Date, td.State, relationsFormatted, td.Summary, td.Context, 463 | td.ImpactTech, td.ImpactBus, td.Symptoms, td.Severity, td.PotentialRisks, td.ProposedSol, 464 | td.CostDelay, td.Effort, td.Dependencies, td.Additional) 465 | } 466 | 467 | // generatePDF generates a PDF file using the gofpdf library 468 | func generatePDF(td TechnicalDebt, filename string) error { 469 | pdf := gofpdf.New("P", "mm", "A4", "") 470 | pdf.AddPage() 471 | 472 | // Set font and size for the title 473 | pdf.SetFont("Arial", "B", 16) 474 | pdf.Cell(40, 10, "Technical Debt Record") 475 | pdf.Ln(12) 476 | 477 | // Add sections to PDF 478 | addPDFSection(pdf, "Title", td.Title) 479 | addPDFSection(pdf, "Author", td.Author) 480 | addPDFSection(pdf, "Version", td.Version) 481 | addPDFSection(pdf, "Date", td.Date) 482 | addPDFSection(pdf, "State", td.State) 483 | addPDFSection(pdf, "Relations", strings.Join(td.Relations, ", ")) 484 | addPDFSection(pdf, "Summary", td.Summary) 485 | addPDFSection(pdf, "Context", td.Context) 486 | addPDFSection(pdf, "Technical Impact", td.ImpactTech) 487 | addPDFSection(pdf, "Business Impact", td.ImpactBus) 488 | addPDFSection(pdf, "Symptoms", td.Symptoms) 489 | addPDFSection(pdf, "Severity", td.Severity) 490 | addPDFSection(pdf, "Potential Risks", td.PotentialRisks) 491 | addPDFSection(pdf, "Proposed Solution", td.ProposedSol) 492 | addPDFSection(pdf, "Cost of Delay", td.CostDelay) 493 | addPDFSection(pdf, "Effort to Resolve", td.Effort) 494 | addPDFSection(pdf, "Dependencies", td.Dependencies) 495 | addPDFSection(pdf, "Additional Notes", td.Additional) 496 | 497 | // Output the PDF 498 | err := pdf.OutputFileAndClose(filename) 499 | if err != nil { 500 | return fmt.Errorf("error saving PDF file: %w", err) 501 | } 502 | return nil 503 | } 504 | 505 | // addPDFSection adds a section to a PDF document 506 | func addPDFSection(pdf *gofpdf.Fpdf, title, content string) { 507 | pdf.SetFont("Arial", "B", 12) 508 | pdf.Cell(40, 10, title+":") 509 | pdf.Ln(8) 510 | pdf.SetFont("Arial", "", 12) 511 | pdf.MultiCell(0, 10, content, "", "", false) 512 | pdf.Ln(6) 513 | } 514 | 515 | // generateExcel generates an Excel file using the excelize library 516 | func generateExcel(td TechnicalDebt, filename string) error { 517 | f := excelize.NewFile() 518 | 519 | // Create a sheet 520 | sheet := "TechnicalDebt" 521 | index, _ := f.NewSheet(sheet) // Corrected: In excelize v2, NewSheet returns only an int 522 | 523 | // Set headers 524 | headers := []string{ 525 | "Title", 526 | "Author", 527 | "Version", 528 | "Date", 529 | "State", 530 | "Relations", 531 | "Summary", 532 | "Context", 533 | "Technical Impact", 534 | "Business Impact", 535 | "Symptoms", 536 | "Severity", 537 | "Potential Risks", 538 | "Proposed Solution", 539 | "Cost of Delay", 540 | "Effort to Resolve", 541 | "Dependencies", 542 | "Additional Notes", 543 | } 544 | 545 | for i, header := range headers { 546 | cell, _ := excelize.CoordinatesToCellName(i+1, 1) 547 | f.SetCellValue(sheet, cell, header) 548 | } 549 | 550 | // Set values 551 | values := []string{ 552 | td.Title, 553 | td.Author, 554 | td.Version, 555 | td.Date, 556 | td.State, 557 | strings.Join(td.Relations, ", "), 558 | td.Summary, 559 | td.Context, 560 | td.ImpactTech, 561 | td.ImpactBus, 562 | td.Symptoms, 563 | td.Severity, 564 | td.PotentialRisks, 565 | td.ProposedSol, 566 | td.CostDelay, 567 | td.Effort, 568 | td.Dependencies, 569 | td.Additional, 570 | } 571 | 572 | for i, value := range values { 573 | cell, _ := excelize.CoordinatesToCellName(i+1, 2) 574 | f.SetCellValue(sheet, cell, value) 575 | } 576 | 577 | // Set active sheet 578 | f.SetActiveSheet(index) 579 | 580 | // Save the Excel file 581 | if err := f.SaveAs(filename); err != nil { 582 | return fmt.Errorf("error saving Excel file: %w", err) 583 | } 584 | return nil 585 | } 586 | 587 | func main() { 588 | // Define command-line flags 589 | formatPtr := flag.String("format", "markdown", "Output format: markdown, ascii, pdf, excel") 590 | filenamePtr := flag.String("output", "", "Output filename (optional)") 591 | emptyPtr := flag.Bool("empty", false, "Generate an empty template") 592 | flag.Parse() 593 | 594 | // Check if help is requested 595 | if len(os.Args) > 1 { 596 | for _, arg := range os.Args[1:] { 597 | if arg == "-h" || arg == "--help" { 598 | usageText := `Usage: generate_td [OPTIONS] 599 | 600 | Generates a technical debt record in the specified format. 601 | 602 | Options: 603 | -format string 604 | Output format: markdown, ascii, pdf, excel (default "markdown") 605 | -output string 606 | Output filename (optional). If not provided, a default filename with the appropriate extension is generated. 607 | -empty 608 | Generate an empty template with placeholders without prompting for input. 609 | -h, --help 610 | Show this help message and exit. 611 | 612 | Examples: 613 | Generate a Markdown file: 614 | generate_td -format markdown 615 | 616 | Generate a PDF file with a custom filename: 617 | generate_td -format pdf -output my_debt_record.pdf 618 | 619 | Generate an Excel file with an empty template: 620 | generate_td -format excel -empty 621 | 622 | Show help: 623 | generate_td --help 624 | ` 625 | fmt.Print(usageText) 626 | return 627 | } 628 | } 629 | } 630 | 631 | // Supported formats 632 | supportedFormats := map[string]bool{ 633 | "markdown": true, 634 | "ascii": true, 635 | "pdf": true, 636 | "excel": true, 637 | } 638 | 639 | // Validate format 640 | format := strings.ToLower(*formatPtr) 641 | if !supportedFormats[format] { 642 | fmt.Println("Unsupported format. Supported formats are: markdown, ascii, pdf, excel") 643 | return 644 | } 645 | 646 | // Map formats to file extensions 647 | formatExtensions := map[string]string{ 648 | "markdown": ".md", 649 | "ascii": ".txt", 650 | "pdf": ".pdf", 651 | "excel": ".xlsx", 652 | } 653 | 654 | // Determine output filename 655 | var filename string 656 | if *filenamePtr != "" { 657 | ext := filepath.Ext(*filenamePtr) 658 | if ext == "" { 659 | // Append the correct extension 660 | filename = *filenamePtr + formatExtensions[format] 661 | fmt.Printf("No file extension provided. Appending '%s' to the filename.\n", formatExtensions[format]) 662 | } else { 663 | // Check if the extension matches the format 664 | expectedExt := formatExtensions[format] 665 | if strings.ToLower(ext) != expectedExt { 666 | fmt.Printf("Warning: The provided filename extension '%s' does not match the format '%s'. Expected '%s'.\n", 667 | ext, format, expectedExt) 668 | } 669 | filename = *filenamePtr 670 | } 671 | } else { 672 | // Generate default filename 673 | filename = "technical_debt_record" + formatExtensions[format] 674 | } 675 | 676 | // Create an empty technical debt record if the -empty flag is set 677 | td := TechnicalDebt{Empty: *emptyPtr} 678 | 679 | // If not generating an empty file, prompt user for inputs 680 | if !*emptyPtr { 681 | var err error 682 | 683 | td.Title, err = getInput("Enter the Title of the Technical Debt: ", true) 684 | if err != nil { 685 | fmt.Println("Error reading title:", err) 686 | return 687 | } 688 | 689 | td.Author, err = getInput("Enter the Author of the Document: ", true) 690 | if err != nil { 691 | fmt.Println("Error reading author:", err) 692 | return 693 | } 694 | 695 | td.Version, err = getInput("Enter the Version (e.g., 1.0.0): ", true) 696 | if err != nil { 697 | fmt.Println("Error reading version:", err) 698 | return 699 | } 700 | 701 | // Prompt for Date with default as today 702 | dateInput, err := getInput("Enter the Date (YYYY-MM-DD) [Leave blank for today]: ", false) 703 | if err != nil { 704 | fmt.Println("Error reading date:", err) 705 | return 706 | } 707 | if dateInput == "" { 708 | td.Date = time.Now().Format("2006-01-02") 709 | } else { 710 | // Validate date format 711 | _, err := time.Parse("2006-01-02", dateInput) 712 | if err != nil { 713 | fmt.Println("Invalid date format. Please use YYYY-MM-DD.") 714 | return 715 | } 716 | td.Date = dateInput 717 | } 718 | 719 | // Get State 720 | td.State, err = getState() 721 | if err != nil { 722 | fmt.Println("Error reading state:", err) 723 | return 724 | } 725 | 726 | td.Relations, err = getRelations() 727 | if err != nil { 728 | fmt.Println("Error reading relations:", err) 729 | return 730 | } 731 | 732 | // Additional fields 733 | td.Summary, err = getInput("Enter Summary: ", false) 734 | if err != nil { 735 | fmt.Println("Error reading summary:", err) 736 | return 737 | } 738 | 739 | td.Context, err = getInput("Enter Context: ", false) 740 | if err != nil { 741 | fmt.Println("Error reading context:", err) 742 | return 743 | } 744 | 745 | td.ImpactTech, err = getInput("Enter Technical Impact: ", false) 746 | if err != nil { 747 | fmt.Println("Error reading technical impact:", err) 748 | return 749 | } 750 | 751 | td.ImpactBus, err = getInput("Enter Business Impact: ", false) 752 | if err != nil { 753 | fmt.Println("Error reading business impact:", err) 754 | return 755 | } 756 | 757 | td.Symptoms, err = getInput("Enter Symptoms: ", false) 758 | if err != nil { 759 | fmt.Println("Error reading symptoms:", err) 760 | return 761 | } 762 | 763 | td.Severity, err = getInput("Enter Severity (Critical / High / Medium / Low): ", false) 764 | if err != nil { 765 | fmt.Println("Error reading severity:", err) 766 | return 767 | } 768 | 769 | td.PotentialRisks, err = getInput("Enter Potential Risks: ", false) 770 | if err != nil { 771 | fmt.Println("Error reading potential risks:", err) 772 | return 773 | } 774 | 775 | td.ProposedSol, err = getInput("Enter Proposed Solution: ", false) 776 | if err != nil { 777 | fmt.Println("Error reading proposed solution:", err) 778 | return 779 | } 780 | 781 | td.CostDelay, err = getInput("Enter Cost of Delay: ", false) 782 | if err != nil { 783 | fmt.Println("Error reading cost of delay:", err) 784 | return 785 | } 786 | 787 | td.Effort, err = getInput("Enter Effort to Resolve: ", false) 788 | if err != nil { 789 | fmt.Println("Error reading effort:", err) 790 | return 791 | } 792 | 793 | td.Dependencies, err = getInput("Enter Dependencies: ", false) 794 | if err != nil { 795 | fmt.Println("Error reading dependencies:", err) 796 | return 797 | } 798 | 799 | td.Additional, err = getInput("Enter Additional Notes: ", false) 800 | if err != nil { 801 | fmt.Println("Error reading additional notes:", err) 802 | return 803 | } 804 | 805 | // Validate inputs 806 | if err := validateTechnicalDebt(td); err != nil { 807 | fmt.Println("Validation error:", err) 808 | return 809 | } 810 | } 811 | 812 | // Generate content based on format 813 | switch format { 814 | case "markdown": 815 | content := generateMarkdown(td) 816 | err := os.WriteFile(filename, []byte(content), 0644) 817 | if err != nil { 818 | fmt.Println("Error generating Markdown file:", err) 819 | return 820 | } 821 | case "ascii": 822 | content := generateASCII(td) 823 | err := os.WriteFile(filename, []byte(content), 0644) 824 | if err != nil { 825 | fmt.Println("Error generating ASCII file:", err) 826 | return 827 | } 828 | case "pdf": 829 | err := generatePDF(td, filename) 830 | if err != nil { 831 | fmt.Println("Error generating PDF file:", err) 832 | return 833 | } 834 | case "excel": 835 | err := generateExcel(td, filename) 836 | if err != nil { 837 | fmt.Println("Error generating Excel file:", err) 838 | return 839 | } 840 | default: 841 | fmt.Println("Unsupported format.") 842 | return 843 | } 844 | 845 | fmt.Printf("\nTechnical Debt record has been saved to '%s'.\n", filename) 846 | } 847 | --------------------------------------------------------------------------------