The Rust programming language
Background
Days when you work on a proposal for client are so different from the days you work on a tough programming challenge. Aren’t they so different style of thinking? While working on proposals for client the pesky power point alignments, crunching the content, effort, schedule, competitor offerings and many such things circle in head. The worst of them is coordinating with other teams in the organization for their content, effort etc. is so dizzying. On the other hand, working on a programming task the algorithm, data structures, memory foot print, optimisation, right libraries etc. circle on head.
Pinnacle in the trade of software development is scaled when one can balance these two traits.
A potential customer wanted us to create a software to manage operations in planning an event. The events they conduct range from rock shows, talk shows, corporate conferences, festival shows etc. Nature of operations these shows involve vary a lot but there are similarities as well. Customer insisted on having a solution that they could customize as time progressed. Target software was to manage short term contracts with suppliers who work on an event, organize the logistics, manage inventory of items that get deployed to a site, manage schedule for various activities in the event, and much more.
The challenging ask among those features was the ask to simulate failures in logistics. Provided an activity which was planned is not performed per schedule the simulator was to instruct what are the contractual impacts to the event both on the receivable and on payable sides. Customer was not all green field where a system was to be constructed. Staffs in the customer organization had their own off the sleeve tricks that help them measure such impact part in orderly manner and part from the experience.
It was relatively boring for us to flash a deck on the big screens and say that it will take so much days and cost you so much etc. kind of talk. We noticed that client was so deeply pinched by the problem that they might not believe all such talk unless they see something accomplishing this on their screens.
This spurred our interests and we took the concept for a spin and boast off in due process as well!
We did that by prototyping the simulator and packed it within a presentation slot of 30 mins where conversations on other topics related to engagement supposed to take place. Our hunch on the sales pitch was that client will connect much better with the solution when they could see key challenges getting addressed. Plus, we chose Rust as a language of choice to demonstrate this simulator. The idea was to close the pitch with a remark on our team’s ability to learn and re-learn things as we go along accomplishing our goals for the customer. We hoped that this goes across the board as a positive sign for a team. What happened is a tea time talk for another day but what will be interesting is the talk on what we envisioned as a differentiating prototype and how we accomplished that in Rust.
Pick a problem!
We have talked about Rust earlier. We create a simple library to be packaged as web assembly for re-use. Given that comfort level we will pick the language to model our scenario. One of the toughest problems in software development is to articulate the real-life scenario in such an effective manner that the solution we produce addresses every inch of details on that scenario.
We take a stab here in articulating the scenario first then take it to Rust with commentary on what ran in our heads while we prototyped it.
The point which we felt could impress if we demonstrate is the ability to create short term contracts with relevant clauses and attach it to the logistics. Once we have this established the impact of logistics failure could be modelled easily afterward. Challenge was many off the sleeve tricks and experience staff used focused on drilling down a particular entity let us a contract or on logistics of a vendor. Sheer multiplicity of contracts to a show to logistics was so deep that a trick itself could have become punishment for the staff to go down that rabbit hole. This challenge had all the right ingredient for demonstration of capabilities – complexity, value to the customer, low hanging fruit that can be solved quickly.
We started with modelling the domain first instead of worrying about the flow of data. Though, that was another fish to fry but was lot bigger one.
Approach
Our deliberation started with what is a contract for the customer? Is it a scanned document, or is a verbal commitment or is it a record registered with a legally binding authority or something else? The other point one of us reminded to not loose sight was the adjective – “short term” contracts. There few answers that we could mull over without asking them as question back to customer yet. We played out ruling out the obvious ones – It cannot be a record that is registered with legally binding authority. Because of the adjective “short-term”. If it was registered it will take time and that way of working will not bind well with business that customer was into. The other one more plausible was if we assume it is a scanned document, we will need NLP capability to extract data. Thus, crux of our demonstration will shift from solving the logistic failure impact to parsing images / pdf files to plain text. As such that is error prone and we did not want to bet our time on solving that problem. On similar reasoning we ruled out the verbal commitment as well. That left us with something else. For everyone’s sake we assumed (it is a big assumption) that data for contracts will be keyed in.
Don’t jump in to say will it mean they can enter the contract and logistic arrangement details and the problem is solved? The answer is simply No.
Though we are making an assumption. We cannot assume that customer will solve the problem by themselves right! There is this unsaid practice of making only practical assumptions. The implieswe can now focus on defining the type for contract.
We start like this –
use datetime::{LocalDateTime} struct contract { supplier: String, enforced_date: LocalDateTime, expiry_date: LocalDateTime, contract_value: u16 }
|
Well, struct is a template which defines the inner details of an entity. Contract in this case. We cooked up the property that are basic and are basic required fields. Remember we haven’t interviewed the customers and neither at this stage have the opportunity to do so.
Let us hypothesize for a moment about nature of these contracts. The givens to us are – they are contracts related to conducting an event. That implies these could be contracts for materials, labour, performing stars, catering, ticketing, and many more. How do we reflect this in the model above? Options are –
enum contract_type { material, labour, performers, catering, venue, ticketing }
|
Or we could use this
… struct contract { … type: String }
|
From conveying the message perspective, the 2nd option is more convoluted whereas the first one is more expressive. But that expression comes at cost –
The first cost is okay and in fact it is not an impact because a contract will never be both at any point in time. The more practical thing is a single supplier can enter into contract of different types. By keep this exclusivity of a contract type to a singular option we are ensuring that we even accidentally do not corrupt any behaviours we define for the type.
So, what could be behaviours for contract? We have paused momentarily our thoughts on the second cost element and started wondering when we say corrupt behaviours is it worth thinking about it? Behaviours can be
Let us run with these; there are couple of ways to realize these behaviours –
impl contract { fn active(&self) -> bool { … } fn annule(&self) { … } }
|
Another is via traits
pub trait enforce_contract { fn active(&self) -> bool; fn annule(&self); }
|
The pivoting difference is how much generic do we want these behaviours and what other types will share this behaviour. The first approach binds the behaviours to the type i.e., contract and the second approach keeps that binding for a latter time. The next question will be when will it bind such behaviours? Until it encounters something like this –
impl enforce_contract for contract { … }
|
Notice that we are sort of mapping the trait for a type i.e., contract. This means if we define a new type let us say –
struct logistics { … }
|
We can technically do this –
impl enforce_contract for logistics { … }
|
Though we could do that technically but does that make sense? Probably not. But are there such behaviours which spans across multiple types in our domain? Probably yes. That begs for the question what are the other types or entities that we have in this domain, we park that for next dispatch