Beyond Object theory, into code implementation— Part 3

Overmind
Overmind_xyz
Published in
9 min readJun 30, 2023

Conventions, code cleanliness, minimizing technical debt — what separates excellent and average devs

Now that you have the theory, the last part of the series is mostly focused good coding practices and, hopefully equally as good, humour. If you have followed the first two parts of the series, then you should have no issues completing the quest Longswords and Dragons on the Overmind platform. The quest makes extensive use of property maps in order to calculate evolutionary numbers for hatching dragons and combining swords. Given its complexity, close to 1000 lines of code instead of the usual 250ish lines, we expected spaghetti code and boy, did we stock up our pantry.

Technical Debt and Spaghetti Code

As projects become more complex and require more collaboration, it is very easy to build a project like the one pictured below. And there is a steep cost associated with bad code.

Imagine a plate of spaghetti, you pour some sauce on it and twist it around a couple of times to get it all coated. Then you look at a single strand of spaghetti and wonder, where does this go? Then you go on a mission to find both ends of this strand of spaghetti. You dig through the piles of other spaghetti strands, you place some break points in this strand of spaghetti and finally you give up trying to make any logical sense of this entire plate of spaghetti and dump it in the trash in order to create something new, something less…. twisty, than that plate of spaghetti.

A good visual representation of this phenomenon comes from this VincentDNL comic:

Sometimes, instead of spaghetti code, we have spaghetti programs. In an agile focused world with weekly stand ups, we become feature focused. When everyone is building features, we lose sight of the structure of the house and how one part logically connects the other. After all, the project managers got that handled. If they want the house to be waterproof, then why bother finishing the roof when it’s faster to duck tape an umbrella over the hole? Feature complete.

This is where we get into technical debt. “Debt” is rather financial in nature and hints at the “cost of code”. We take the average salary of a developer, find the hourly rate and the number of hours it takes to complete a feature and we have this cost. However, when code is badly written, it is difficult to read, following the spaghetti issue, and it is prone to breaking in unexpected situations causing all number of patches and hot fixes. Now, you are not just paying for the feature, but the time it takes for the developer, or his successor, to understand the code base and do maintence and damage control. Lastly, a point that the comic illustrates, when you try to add new features, the code base is so brittle to changes, that it is almost impossible to add without causing a collapse or reducing the technical debt first.

For all of Overmind’s quests, the TODOs should guide you to think in a structured way along with learning Move concepts. All of our structs, constants and function variables are named in a way which gives clues about the underlying logic of the system.

Pro Tip: Solution code will be posted on Github for education quests and in depth explanations are provided in our quest library upon closing of the quest.

For users who have solved multiple quests, all modules follow the same structure to aid in understanding of the quest. Let’s take a deep dive.

Respect Conventions

Keeping different sections of code open on different monitors, or window displays for those of us with only one device, can help immensely in maintaining the general context in mind and also quickly find recurring pieces of code like constants and assert functions as you go through the main functions. Personally, I have 1 monitor which I switch between constants and error codes on top and assert functions and helper functions towards the end, while I complete the main functions on my laptop. Find your own comfortable split of the module structure!

A good module structure which each of our quests use is:

  1. Import statements — ordered like the Move Reference Documentation, first by the module’s onchain address (0x1–0x4), then alphabetically by the name of the module. Some modules, for example aptos_token, have the same name but live under different addresses, therefore first ordering by address helps developers raise a flag in their mind. In these cases of same naming, using aliases is very important to differentiate the modules when referring to them in execution code. Check out the uses and aliases chapter on our Move voyage fundamentals.
  2. Import statements (test only) — For modules only used within test functions, list them after the main imports. Making this differentiation saves cost because modules used in testing do not get compiled into bytecode. Saves gas, saves storage.
  3. Error codes — Move allows definition of custom error codes which can be directly used in testing or wrapped in the error library. Error codes and assertion functions usually match in order.
  4. Constants — all the constants that the program needs. Constants are always all in capital letters and separated by underscore.
  5. Module structs — these are the resources that the module can define. When defining these resources go from general to specific. For example, system management resource first, then specific resources in the system, followed by secondary resources that the top level ones need.
  6. Main functions — functions supporting the core execution of your product. Organise these functions according to the flow that a user may use your product. Almost always, the init function will come first to ensure proper system setup, kind of like booting up your computer. Taking Longswords and Dragons as an example, the create collection functions were first followed by create token functions. This is because collections must be created before the token since the token creation function requires the input of the collection it belongs to. Following creation, users generally want to breed more dragons or upgrade their swords. Logically, breeding happens before hatching so we have those two functions followed up with the combine sword function.
  7. View functions — these functions gives an indication of what data the users will see in the frontend. Organise them according to where they are called in the main functions.
  8. Helper functions — similar to view functions in ordering. Helper functions often abstract away repetitive workflows or unused concepts. For example, the Longswords and Dragons quest does not use the royalty object and does not mutate any properties. Hence, there is the create_collection_internal function to abstract these input parameters away when dragon and sword tokens are created.
  9. Assert functions — as mentioned in error codes, assert functions are sorted according to error codes they throw. Secondarily, they follow the flow of the main functions.

Tests are last in modules, however, some may choose to put them in a separate file for readability. If you look at the Aptos Github, you may also notice specification functions which are not covered in our quests.

There is more to be said about Move coding conventions, a lot of naming cases to learn like all caps for constants, lower snake case for functions, etc. However, as a first step, learn to give your variables meaningful names. Imagine if you had to read someone’s code and the variables are named a, b, c, d. Nobody can make sense of that. Except compilers. That’s why Javascript files often gets minified — to save storage space on the browser cache and to obfuscate internal logic. As we are humans, name your variable as close to what it is as possible. It is preferable to have a long name like “token_collection_for_dragon_race_era_one”, than just “a”. Remember that technical debt we talked about? Help your fellow developers understand your code and reduce technical debt. Less developer frustration leads to less add-ons and workarounds, meaning less redundant code getting archived into Github’s Arctic Vault - even good for the planet!

Experienced developers are self sufficient — here’s how

Going full ironic, and possibly hypocritical, for a moment, junior devs need a lot more assistance through code reviews, peer coding, various tutorial content, ahem this Medium post, while more experienced devs are able to read Github, some Pull Requests and they are good to go. This is not an uncommon phenomenon. On average, a professional philharmonic orchestra only meets 2 or 3 times as a full orchestra before they are on stage, wowing the audience. Luckily, there is a happy in between which can help junior devs sharpen their code reading skills.

Look at the Reference Documentation before cross referencing with Github. The reference documentation provides a handy list of functions and structs at the beginning to allow for a speedy overview of what the module is about. The drawback is that it will not include internal functions and the tests. Think of reading reference documentation like a user guide index, its what the developers interacting with the module care about. Head over to Github for the internal machinations of the module. Some modules, like Property Map has an entire internal type system.

Tests are not only valuable in the official Aptos Github repos but in every situation, aka, when you do a quest. When in doubt of how a function is used, look into the test functions to see what is initialized before the test, what are the function inputs and assertion results. Assertions are not just for catching errors - they imply what the expected outcome of the test should be.

Lastly, there is no shame in asking for help, but ask for help in a way that allows others to help you. Sure, it is always recommended to have a guidance space of “no stupid questions” like office hours, peer coding sessions, mentorship, etc. but in a collaborative space like Discord where the devs are already overworked and under pressure, the fastest way to getting help is to:

  1. Ask your question in a straight to the point manner
  2. Indicate the lines of code where the question arises — do NOT dump a whole coding project with thousands of lines.
  3. If question is an error, a description of how others can reproduce the error

At Overmind, we are more of a safe space for beginner devs kind of Discord but certainly not every online platform is like that and we encourage our users to get better at asking for help as this skill is critical in open source collaboration.

Developer reputation through open source collaboration

In my years of interacting with Dev communities, I often here the sentiment, “it was so great to meet <insert Github handle> at the conference. Worked with him forever, nice to finally put a face to such a great guy!”

In fact, a lot of people prefer to be called by their aliases even in a face to face setting. These devs live and breathe and eventually adopt their open source persona into their identity. While not everyone is this fanatical, building an open source reputation in your community of interest will go a long way in establishing your credibility when applying for jobs or applying to become maintainers of huge open source projects like Linux.

A more specific reason before we dive into the how of open source collaboration, in the blockchain industry changes are lightening speed. It is definitely the early bird that gets the worm. Ask yourself, do you know about the last five AIPs in Aptos?

In fact, at the time of writing this series, the create_object_from_account function is already marked deprecated. Aptos will move towards generating UUIDs from transaction contexts (post for another day) instead of account generated GUIDs. This was hinted at in AIP-36 and development is ongoing at full speed. As developers, it is important to watch and follow the Github repository of AIPs, if not in addition to the PRs of Aptos Core repository. If this was not convincing enough, want a job? Github repos are a direct line to the internal devs of any project.

So how does one go about building a good Github profile and collaborate appropriately? Github has comprehensive rules and roles in working with PRs, but for starters, fill your Github profile with a wide selection of interesting projects. Fork some to give you a starting boost and add your own features to it. For the publicly released quests of Overmind, we encourage users to build their own product!

In the process of building projects for your profile, you will run into questions and issues. Start a discussion in Discord, log an issue or even just making a comment on a PR is huge in the decentralized Blockchain world. Stay engaged, build reputation.

--

--

Overmind
Overmind_xyz

The first web3 solve-to-earn platform where developers compete on coding puzzles to earn prizes and on-chain credentials. Live on #Aptos.