@@ -20,6 +27,8 @@ Based on our own preliminary research on what was already being done in the SSI
1. I wanted to learn a new programming language. I had a lot of experience from javascript and wanted to challenge myself.
2. Rust had an up-to-date implementation of the DIDComm v2 specification called `didcomm-rs`, whereas javascripts implementation of the same spec was outdated by 6 months. See https://github.com/decentralized-identity/didcomm-rs vs https://github.com/decentralized-identity/didcomm-js.
## 1.2 Strengths and weaknesses of Rust
### 1.2.1 Strength: Catches errors at compile-time
...
...
@@ -32,7 +41,6 @@ Here are some examples of errors caught at compile time:
Catching errors as early as possible saves development time and increases iteration speed. You could say that runtime errors are costly and compile time errors are cheap.
### 1.2.2 Strength: Fast
Rust is fast because it enables low-level programming and compiles all code ahead of runtime. No Just-in-time compilation. The Rust compiler is considered on par with any modern C compiler. Achieving this has been quite a feat for Rust, since C has been considered the state-of-the-art performance programming language for decades. Example benchmark of Rust vs C here: https://levelup.gitconnected.com/which-is-faster-rust-or-c-lets-find-out-who-is-the-usain-bolt-87495c774c8.
...
...
@@ -88,7 +96,9 @@ At least from my own experience, getting into Rust was like getting hit by a bri
Again the Rust Community Discord server helped me through the steepest part of the learning curve. Thank you https://discord.com/invite/rust-lang-community :pray:
### 1.3 How we controlled process and communication systems during development
## 1.3 How we controlled process and communication systems during development
-**Discord** - Most live discussion was conducted in Decentralized Identity Norden (DIN) Discord server.
-**Slack** - DIN also had a Slack-server, but this was never utiliized throughout the project period. DIF on the other hand, did most of their discussions through their Slack server.
...
...
@@ -98,7 +108,8 @@ Again the Rust Community Discord server helped me through the steepest part of t
-**Email** - Before getting into DIFs Slack-channel, there was a need to get in touch with some of the DIF-guys to ask questions about which direction the project should go in. We wanted to avoid doing uninteresting things. Snorre, which was the projects product manager, had some contact information to reach these key-industry-experts via email. The conversation always started with Snorre sending an email to one of these experts, with me (Jonas) as a CC-recipient, introducing me.
### 1.4 Use of version control systems, ticket tracking, branching, tagging/versioning
## 1.4 Use of version control systems, ticket tracking, branching, tagging/versioning
<imgsrc="./github-kanban.png"width=600>
...
...
@@ -107,13 +118,14 @@ Again the Rust Community Discord server helped me through the steepest part of t
-**Github Branching** - As only one developer was working on this project, throughout the entire period, most issues were resolved directly on the main branch. The few times a separate branch was created, was when bigger milestones were implemented - Example: When DID CLI was first conceived, it was being worked on on a separate branch for quite a while. Also there were alot of `playground/<miniproject>` branches in the beginning, for experimentation with different SSI-technologies. It was good to keep the experimentation in a separate branch. Because this made it easy to kill experiments, if they turned out to be a dead end.
### 1.5 Programming style guide including how to comment code
## 1.5 Programming style guide including how to comment code
- We are using the Rust official style guide found here - https://doc.rust-lang.org/1.0.0/style/style/README.html
- We are following the official style guide religiously and want to avoid in-house style guides.
- Sticking to the offical one makes it easier and faster to onboard new developers.
### 1.6 Use of and integration of libraries, modules, and other ways for modularisation of your product
## 1.6 Use of and integration of libraries, modules, and other ways for modularisation of your product
One of the goals of the project, was to re-use as much as possible of existing libraries from the SSI community. This was the main reason Rust was chosen in the first place. The SSI community are already heavily invested into Rust, for many of the same strengths mentioned in section 1.
...
...
@@ -124,17 +136,19 @@ One of the goals of the project, was to re-use as much as possible of existing l
### 1.7 Use of code review
## 1.7 Use of code review
- Pull Requests in Github is at the center of the code review process. Ideally there should be one pull request attached to every branch.
- When the pull request has received a code review, it could either be approved or receive a change-request.
- Once code review is approved, the pull request is merged, closed, the branch gets deleted, and the attached issue-ticket gets a status change from "In-review" to "Done"
## 2 Individual discussion
First I would like to say that both chapter 1 and 2 of this report is individual discussion, as I was working alone as the only developer on DID CLI.
### 2.1 A link to, and discussion of, code you consider good
Since our implementation is a Command-Line interface, there is a need to run different functionality depending on which command the user selects. The `run()`-function above is responsible mapping commands and arguments to a runnable function. It is basically a giant switch. So why do I like this piece of code?:
-**Decouples input-logic from application-logic** - The `run()`-function decouples application-logic from the `Config`-struct generated by the input-parsing code. In the `run()`-function one would be tempted to just pass the `Config` directly as an argument to all the underlying application functions. like `connect(config)`, `did(config)`, etc. This would then introduce the `Config`-struct as a dependency to the large parts of the codebase, making changes to the `Config`-struct potentially lead to very broad changes. By not falling into this temptation, and instead being very specific about which arguments are passed furteher on to the underlying functions, we avoid this trap, and the coupling between input-code and application-code remains very low. In pratice this means that if we change the layout of the `Config`-struct, most of the time we only have to change how the `run()`-function passes it's arguments further down the pipeline, leaving most of the codebase untouched. Decoupling is important in a collaborative environment. Decoupling makes the distinction between different parts of the codebase clear, and makes it easier for multiple people working on the codebase at the same time, without stepping on each others toes (merge conflicts).
DID-CLI's init-function starts with creating a bunch of directories, if they don't already exist. There are multiple reasons why this code is bad:
-**No else block** - For every one of these ifs there is an else. In this context getting in the else-block means: "The directory you tried to create already exists.". In this case, the init() function should just exit and do nothing. Instead it continues executing, potentially corrupting existing files. What should have happened here is that the init() function should exit, and then give an error message to the user. Something like this: `"A `.did/`-directory already exists. Do you want to overwrite it? (yes/no)"`.
-**.unwrap()** - In Rust, whenever you are using `.unwrap()`, it means: Succeed or panic on this line and stop execution. This may be ok in many cases. It is not ok in this case and probably it was just done because of lazyness. Failing to create a directory is a potential error that could happen, and it is not a programmers error. Therefore we should have a way to recover from the error. Maybe give an error to the user and ask if he wants to "try again?". Also if the creation of directory number 3 fails, after 1 and 2 succeeded, there should be a cleanup of directory 1 and 2, before exiting the program. Leaving 1 and 2 there without a directory 3 and 4 is not a valid state for the application to be in. Either no directories should be present or all 4. In database-terms: The directories should be created as a single transaction, and the transaction should be rolled back to the initial state, if anything fails during the transaction.
### 2.3 A link to two pieces of code, a before and after refactoring.
As expected, the reduction in responsibilities for the `read`-command, and the introduction of the new single-responsibility `hold`-command, made both commands simple. Fewer lines of code per function, fewer distinct steps per function, easier to reason about.
Also supporting optionally reading input from `stdin`, made all commands compatible with Unix pipelines, which made the entire DID CLI more convenient to use together with existing Unix tools such as `cat`, `echo`, `curl`.
### 2.4 Personal reflection about professionalism in programming
In general, professionalism in programming is about paying attention to what works and what does not, and then do more of what works and less of what does not work.