Looking inside Traits
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
Recent post
Archives
- November 2024
- October 2024
- September 2024
- August 2024
- July 2024
- June 2024
- October 2023
- June 2023
- March 2023
- February 2023
- January 2023
- December 2022
- November 2022
- October 2022
- September 2022
- August 2022
- July 2022
- June 2022
- May 2022
- April 2022
- March 2022
- February 2022
- January 2022
- December 2021
- November 2021
- October 2021
- September 2021
- August 2021
- July 2021
- June 2021
- May 2021
- April 2021
- January 2021
- December 2020
- October 2020
- August 2020
- June 2020
- May 2020
- April 2020
- March 2020
- February 2020
- January 2020
- December 2019
- November 2019
- October 2019
- September 2019
- August 2019
- July 2019
- June 2019
- May 2019
- April 2019
- March 2019
- February 2019
- January 2019
September 15, 2021