/
Thunderjet - Tech Debt

Thunderjet - Tech Debt

What is tech debt

Ward Cunningham coined the term. He later explained how he came up with the idea:

“With borrowed money, you can do something sooner than you might otherwise, but then until you pay back that money you’ll be paying interest. I thought borrowing money was a good idea, I thought that rushing software out the door to get some experience with it was a good idea, but that of course, you would eventually go back and as you learned things about that software you would repay that loan by refactoring the program to reflect your experience as you acquired it.”

Generally, technical debt is code or data that can be optimized to improve future development productivity. As such, it can be seen as an opportunity to improve productivity in the long term. Tech debt is often increasing as a result of consistently prioritizing fast feature delivery over code quality. Too much tech debt can prevent fast development, and eventually prevent major improvements entirely. Tech debt can be useful to provide an important feature fast, as long as it is addressed quickly afterwards. Tech debt increases the cost of maintaining and improving a project over its lifetime.

What tech debt is not

Missing features, bugs, performance issues, security issues and stability issues are not tech debt, even though they can be caused by tech debt. Their business value is easier to understand. They should be categorized differently.

Tech debt in Acquisitions

Acquisition modules have been developed for over 7 years. In that time, many refactorings happened to optimize the code, but many others did not because of prioritization.
Often, when new technologies or guidelines were introduced, code was not updated entirely. Instead, it was updated where changes were required, leaving inconsistencies in the code and increasing the number of technologies or guidelines to be aware of to understand the code.
Sometimes developers realized an organization that was effective for a small code base became a hindrance with a large code base, but the issue was not addressed, because by that time it had grown so much that it was impossible to fix within a sprint. Refactorings happened when a developer working on a specific feature realized they were needed to add or update that feature and keep the code readable. They rarely happened with the sole goal of reducing tech debt and improving productivity.
Yet it is often faster to fix similar issues everywhere in one go rather than fixing them little by little as code is getting updated. For instance: to replace ".collect(Collectors.toList())" by ".toList()" in all the code to improve readability with Java 16+ (we are now using Java 21 and there are still hundreds of such occurrences in the code).

FOLIO's situation is not uncommon. Software often grows fast initially, gaining in popularity as features improve quickly and better match new user needs than older competing solutions. Then tech debt increases to the point that the software cannot be improved without a complete rewrite, and soon afterwards it gets replaced by a new competing solution. FOLIO has benefited from competing solutions' slow development speed caused by years of increasing tech debt. It could however be the next casualty if tech debt is not better prioritized.

Priorities

To be addressed, tech debt should be prioritized so that some of it is intentionally worked on in each release. A key factor to prioritize is the estimated gain in productivity in proportion to the amount of work needed. This can be better evaluated by developers, and they can estimate priority during backlog refinement at the same time as points. To keep tech debt in check, the highest priority should be high enough to be above important features.
A common rule is to dedicate 20% of development time to tech debt (see for instance "The DevOps Handbook"). This is assuming a constant effort - if a project has not followed that rule for a while, it should dedicate more. When assigning priorities, we should try to balance them so that we end up working on tech debt for over 20% of the time.
Also, developers should regularly work on creating tech debt tickets (they don't currently do this because the tickets are never worked on).

Some major tech debt projects

  • One important module, mod-orders, has grown far beyond a microservice size. It needs to be split up, but this will be a major undertaking. On top of that, unit tests for mod-orders are all mixed up in the MockServer class, which makes it hard to maintain the tests or separate them. So a project to stop using this class is a prerequisite to splitting mod-orders - but this is a large effort in itself too. The more we wait to split up mod-orders, the harder it will be.

    mod-orders_line_history.png
    mod-orders line history as of March 2025 (created with git-of-theseus)
  • Another important project is the update of integration tests (written in Karate). The techniques we use to write these tests have evolved with time, but we never went back and updated all of the old tests. As a result, we regularly lose time when looking for a test with similar features to copy-paste to use as a template for a new test; and sometimes we copy-paste code that has not been updated, resulting in code quality degradation. Updating all the old tests will take a long time, but it is much easier than the mod-orders work conceptually.

List of tickets

Tech debt tickets should have the tech-debt label. This is a list of such tickets, that are still open. Some of these are more about stability than tech debt (such as optimistic locking), but this list includes them because they have the label. And some might also not be relevant anymore or can no longer be done, but they should be investigated and closed.

Filter: https://folio-org.atlassian.net/issues/?filter=13352


labels = tech-debt
AND status IN (Open, "In Progress", "In Code Review", Draft, Blocked, "IN REFINEMENT", BLOCKED)
AND "development team[dropdown]" = Thunderjet
ORDER BY key ASC

 

As of 3/19/2025:

UXPROD

  • UXPROD-2418 - Support for Editing and deleting package orders

  • UXPROD-2674 - ACQ Screenreader Accessibility improvements - Thunderjet

  • UXPROD-3015 - ACQ Mods - Prevent update conflicts (two automated processes acting on the same record)

  • UXPROD-3161 - Orders - Implementing Optimistic Locking

  • UXPROD-3163 - Part 2 - Finance - Implementing Optimistic Locking

  • UXPROD-3164 - Invoices - Implementing Optimistic Locking

  • UXPROD-3165 - Organizations - Implementing Optimistic Locking

  • UXPROD-3431 - Acquisitions (Thunderjet) - Tech Debt, NFR - Backlog

  • UXPROD-3735 - Remove the dependency between mod-orders and inventory

  • UXPROD-4861 - Update Karate tests

  • UXPROD-5004 - Support for Hosting multiple ECS systems in a single server cluster.

Backend

  • FAT-1106 - Rework API test for mixed order and piece operation

  • FAT-13757 - Remove or fix disabled tests

  • FAT-14657 - Enable a test that was missing in OrdersApiTest.java

  • MODAT-162 - Deny request from standalone tenant to ECS tenant in case of hybrid setups

  • MODEXPS-215 - Calculate and return job next execution date and time for edifact export integration

  • MODFIN-120 - Return only ledgers related to the fiscalYear query param

  • MODFIN-260 - Order rollover erro csv does not include Fund code or POL number

  • MODFIN-356 - CLONE - Improve backend error reporting by including cause in error message systematically

  • MODINVOICE-265 - Unit tests can fail because of async operations

  • MODINVOICE-344 - Make invoiceDate a required field in batchedVoucher model

  • MODINVOICE-553 - Add multithreading support for managing invoice-order relationship during Edifact Import

  • MODINVOSTO-117 - Make paymentMethods property in invoice.json JSON schema an enum (and in organization.json on the organizations module)

  • MODINVOSTO-118 - Can fundDistributions property in acq-models/mod-invoice-storage/schemas/voucher_line.json be eliminated?

  • MODORDERS-374 - Handle poline transition from package to non package and vice versa

  • MODORDERS-375 - Added Validation to poLine and Titles APIs

  • MODORDERS-522 - Receiving API is confusing and implementation is redundant

  • MODORDERS-692 - Refactoring : Rename and move order and order line helpers to the service package

  • MODORDERS-981 - Call checkLocationsAndPiecesConsistency and getFunds only once when opening an order

  • MODORDERS-1037 - Improve backend error reporting by including cause in error message systematically

  • MODORDERS-1097 - Refactor mod-orders based on guidelines

  • MODORDERS-1101 - Rewrite tests and remove MockServer

  • MODORDERS-1116 - Split mod-orders to separate receiving (blocked by MODORDERS-1101)

  • MODORDSTOR-112 - Use sentence case in enums

  • MODORDSTOR-215 - Add required fields to orders and order line JSON schema

  • MODORG-34 - json schema for categories defines type string but folio actually requires UUID

  • MODORGSTOR-33 - Implement encryption of interface credentials

  • MODORGSTOR-109 - Add GET /organizations-storage/interfaces/credentials web API

Frontend

  • UIF-463 - FY rollover fails to start with Firefox

  • UINV-301 - Improve UI error reporting - allow user to copy BE error message to clip board from toast message in UI.

  • UINV-549 - "Set exchange rate" filed cannot be negative in the invoice

  • UIORGS-185 - Prevent the deletion of organization records with related records

Related content