Code documentation: Drawings VS Pseudo-Code VS Bulletpoints VS Mermaid
I'm frequently faced with the challenge of documenting an existing system. But I never figured out what tool is the most effective, so, most of the times, I randomly pick a tool and just go with it. This time, I decided to conduct a small competition.
This is what the competing tools were challenged to describe:
WithdrawalControllersubscribed to RabbitMQ queueswithdraw.evm,withdraw.btcandwithdraw.trxwith methodsWithdrawEvm,WithdrawBtc,WithdrawTrx. Each of these queues message contains single fieldtxId.
WithdrawEvmfirst readstxfrom the database by thetxId, then readssysWalletSecretfrom the database bytx.TenantId.txandsysWalletSecretare then passed toEvmTxManager.SignAndSend, which constructs signed evm tx and sends it viaJsonRpc eth_sendRawTransactionrequest to evm node provided by theGetBlock.
WithdrawBtcreads from the database firsttxby thetxId, thenbtcIdbytx.TenantId.txandbtcIdare then passed toBtcTxManager.Sendwhich constructs self-hosted btc node url using btcId and sends thereJsonRpc sendtoaddressrequest build with data fromtx
WithdrawTrxreads from the database firsttxby thetxId, thensysWalletSecretbytx.TenantId. Then based on whethertx.Typeis equal to "Native" calls eitherTrxTxManager.sendNativeorTrxTxManager.sendTokenwithtxandsysWalletSecret. BothTrxTxManagermethods sendPOST wallet/broadcasttransactionrequest with constructed signed trx tx to the trx node provided by theGetBlock
And here's what I got:
Hand Drawing

Preudo Code
WithdrawalController
withdrawEvm rabbitQueue("withdraw.evm")
tx = db.txBy @txId
sysWalletSecret = db.sysWalletSecretFor 'EVM' tx.TenantId
EvmTxManager.signAndSend tx sysWalletSecret
withdrawBtc rabbitQueue("withdraw.btc")
tx = db.transactionBy @txId
btcId = db.btcIdBy transaction.TenantId
BtcTxManager.send tx btcId
withdrawTrx rabbitQueue("withdraw.trx")
tx = db.txBy @txId
sysWalletSecret = db.sysWalletSecretFor 'TRX' tx.TenantId
if tx.Type == "Native"
TrxTxManager.sendNative
tx
sysWalletSecret
else
TrxTxManager.sendToken
tx
sysWalletSecret
EvmTxManager
signAndSend
signedEvmTx = signedTxFrom @tx @secret
sendJsonRpc getblock.evmNode "eth_sendRawTransaction" signedEvmTx
BtcTxManager
send
sendJsonRpc
selfhosted.btcNode
@btcId
"sendtoaddress"
@tx
TrxTxManager
sendNative
signedTrxTx = signedTxFrom @tx @secret
post getBlock.trxNode "/wallet/broadcasttransaction" signedTransaction
sendToken
signedTransaction = signedTxFrom @tx @secret
post getBlock.trxNode "/wallet/broadcasttransaction" signedTransactionBulletpoints
WithdrawControllerhandles messages fromRabbitMQwithdraw.evm(WithdrawEvm)- SELECTS
txbytxId - SELECTS
sysWalletSecretbytransaction.TenantId - Sends to
EvmTxManager.signAndSend- Creates
signedEvmTx - Sends a
JsonRpcrequesteth_sendRawTransactontoevmNodefromGetBlockprovider.
- Creates
- SELECTS
withdraw.btc(WithdrawBtc)- SELECTS
txbytxId - SELECTS
sysWalletSecretbytx.TenantId - Sends to
BtcTxManager.send- Constructs
self-hostedbtcNodeurl usingbtcId - Sends a
JsonRpcrequestsendtoaddressto the url
- Constructs
- SELECTS
withdraw.trx(WithdrawTrx)- SELECTS
txbytxId - SELECTS
sysWalletSecretbytransaction.TenantId - Calls
TrxTxManagersendTokenandsendNativebased ontransaction.Type- Creates
signedTrxTxfor both native and custom tokens. - Sends it via
POST wallet/broadcasttransactiontotrxNodefromGetBlockprovider
- Creates
- SELECTS
Mermaid Flowchart
flowchart TB
rabbit((RabbitMQ))
db[(Database)]
evmNode(("EVM Node
GetBlock Provider"))
btcNode(("BTC Node
Self-Hosted"))
trxNode(("TRX Node
GetBlockProvider"))
rabbit ----> withdrawEvm -- signedEthTx --> evmNode
withdrawEvm <-. tx, sysWalletSecret .-> db
rabbit ----> withdrawBtc -- url by btcId, tx --> btcNode
withdrawBtc <-. tx, btcId.-> db
rabbit ----> withdrawTrx -- signedTrxTx --> trxNode
withdrawTrx <-.tx, sysWalletSecret.-> dbMermaid Sequence Diagram
sequenceDiagram
autonumber
participant R as Rabbit
participant WC as WithdrawController
participant FS as FinanceService
participant DB
participant E as Executors (EvmTx, BtcTx, TrxTx)
participant N as Nodes (Evm-GetBlock, Btc-SelfHosted, Trx-GetBlocks)
R ->> WC: withdraw.evm (txId)
WC ->> DB: txId
DB ->> WC: tx
WC ->> DB: tx.tenantId EVM
DB ->> WC: sysWalletSecret
WC ->> E: evm.signAndSend
E ->> N: evmSignedTx
R ->> WC: withdraw.btc (txId)
WC ->> DB: txId
DB ->> WC: tx
WC ->> DB: tx.tenant
DB ->> WC: btcId
WC ->> E: btc.send
E ->> N: btcId, tx
R ->> WC: withdraw.trx (txId)
WC ->> DB: txId
DB ->> WC: tx
WC ->> DB: tx.tenant TRX
DB ->> WC: sysWalletSecret
WC ->> E: trx.sendNative
E ->> N: signedTrxTx
WC ->> E: trx.sendToken
E ->> N: signedTrxTxResults
If I'd have to pick a solo winner that would be bullet points.
Writing bullet points was intuitive and fast. Any specialist can understand them. Their tree-like structure, perfectly match the flow of the process, allowing step-by-step investigation of each proccess branch. Finally, they are perfectly git-friendly: can be read with no additional tooling, easy to comment on, and so on.
Paradoxically enough, this is the least fancy tool. To glamorize that a bird-eye mermaid flow chart can be added to the mix. I assume a combination of those two would be the most beautiful and understandable way to create a documentation for an existing code.