Saturday, 27 November 2021

Domain driven design notes - [3] Binding model and implementation



  • Binding model and implementation
    • What good is a model on paper unless it directly aids the development of the running software
    • Model Driven Design
      • Tightly relating the code to an underlying model  gives the code meaning and makes the model relevant
      • The analysis model is not created with design issues in mind, and therefore it is quite impractical for those needs
      • Some knowledge crunching happens during such an analysis, but most of it is lost when coding begins, when the developers are forced to come-up with new abstractions for the design
      • The pure analysis model even falls short of its primary goal of understanding the domain, because crucial discoveries always emerge during the design/implementation effort
      • Pure analysis model gets abandoned soon as coding starts and most of the ground has to be covered again
      • A deadly divide opens between analysis and design so that insight gained in each of these activities does not feed each other
      • Model Driven Design discards the dichotomy of analysis model and design to search out a single model that serves both purposes.Each object in the design plays a conceptual role described in the model
      • Design a portion of the software system to reflect the domain model in a very literal way. Demand a single model that serves both purposes well, in addition to supporting a robust Ubiquitous language
    • Modelling paradigms and Tool Support
      • To make MDD pay off the correspondence must be literal, exact within bounds of human error
      • The real breakthrough of object design comes when the code expresses the concepts of the model
      • It would take several iterations of refactoring and knowledge crunching to distill the important concepts of the domain into a simple, incisive model
    • Letting the Bones show: Why Models Matter to Users
      • Quietly changing data is completely unacceptable in most applications
      • Revealing the model gives user more access to the potential of software and yields consistent predictable behaviour, when a design is based on model that reflects the basic concerns of a user
    • Hands-On Modellers
      • Software development is all design
      • Over separation of responsibility for analysis, modelling, design and programming interferes in the MDD
      • When a modeller is separated from the implementation process, he or she quickly looses a feel for the constraints of implementation
      • Programmers are modellers, so it is better to setup projects such that programmers do good modelling work
      • Anyone responsible for changing code must be able to express model through code
      • Success with MDD is sensitive to detailed design decisions

Friday, 26 November 2021

Domain driven design notes - [2] Communication and the use of language


  • Communication and the use of language
    • A domain model can be the core of a common language for a software project. The model is a set of concepts built up in the heads of people on the project, with terms and relationships that reflect domain insight.
    • Ubiquitous language
      • Across the linguistic divide, the domain experts vaguely describe what they want. Developers, struggling to understand a domain new to them, vaguely understand.
      • The indirectness of communication conceals the formation of schisms, different team members use terms differently but don't realise it.
      • A project faces serious when its language is fractured. Domain experts use their jargon while technical teams have their own.
      • Translation blunts communication and makes knowledge crunching anaemic
      • The over head cost of all the translation, plus the risk of misunderstanding is just too high.
      • The vocabulary of Ubiquitous language includes the name of classes and prominent operations.
      • Same model should supply the language for the developers and domain experts to talk to each other
      • Persistent use of Ubiquitous language will force the models weaknesses in open
      • Use the model as the backbone of the language. Use the same language in diagrams, writing and especially speech
      • Resolve confusion over terms in conversation, in just the way we come to agree on the meaning of ordinary words
      • Recognise that a change in the Ubiquitous language is a change in the model
      • Developers should watch for ambiguity or inconsistency that will trip up the design
      • The language carries knowledge in dynamic form
    • Modelling out loud
      • The detachment of speech from other forms of communication is a particularly great loss because we humans have a genius for spoken language
      • One of the best ways to refine a model is to explore with speech
      • It is vital that we play around with words and phrases, harnessing our linguistic abilities to the modelling effort
      • Our brains seem to be somewhat specialised in dealing with complexity in the spoken language
      • We can exploit out innate talent for grammatical, meaningful language to drive model development
      • Find easier ways to say what you need to say and then take those new ideas back down to the diagrams and code
    • One Team, One Language
      • Domain expert is assumed to be capable to thinking deeply about his field. If sophisticated domain experts don't understand the model, there is something wrong with the model
      • The developers and domain experts can informally test the model by walking through scenarios, using the model objects step by step
    • Documents and diagrams
      • UML diagrams are good at communicating relationships between objects, and they are fair at showing interactions, but they do not convey the conceptual definition of these objects
      • Attributes and relationships are only half the story of an object mode. Behaviour on those objects and the constraints on them are not so easily illustrated
      • Diagrams are means of communication and explanation and they felicitate brainstorming. they serve these ends best if they are minimal.
      • The vital detail about the design is captured in the code
      • Always remember that the model is not the diagram
    • Written design documents
      • Spoken communication supplements the codes rigour and detail with meaning
      • Two general guidelines for evaluating a document:
        • Documents should complement code and speech
          • External documents and diagrams do not affect the behaviour of the program so they fall out of sync
          • Code as a design documents does have its limits. Its behaviour is unambiguous but that does not mean its obvious
          • Other documents need to illuminate meaning, to give insight into large scale structures
        • Documents should work for a living and stay current
          • In addition to saving labour, hand drawn documents have the advantage of feeling casual and temporary
          • Greatest value of the design document is to explain the concepts of the model
          • By keeping documents minimal and focussing them on complementing code and conversation, documents can stay connected to the project
      • Executable bedrock
        • Still, even when code can mislead, it is closer to the ground that other documents
        • To communicate effectively, the code must be based on the same language used to write the requirements-the same language that the developers speak with each other and the domain experts
      • Explanatory model
        • One model should underline implementation, design and team communication

















Thursday, 25 November 2021

Domain driven design notes - [1] Crunching knowledge

  • Crunching knowledge
    • Ingredients of effective modelling
      1. Binding the model to the implementation
      2. Cultivating a language based on the model
      3. Developing a knowledge rich model
      4. Distilling the model
      5. Brainstorming and experimentation
    • It is the creativity of brainstorming and massive experimentation, leveraged through a model based language and disciplined by the feedback loop through implementation, that makes it possible to find a knowledge rich model and distill it. << That was mouthful :D
    • Knowledge crunching
      • Effective domain modellers are knowledge crunchers
      • Many models are tried and rejected or transformed
      • A team of domain experts collaborate, typically led by developers
      • lots and lots of talk
      • Good programmers will naturally start to abstract and develop a model that can do more work
      • The shallowness of knowledge produces software that does basic job but lacks a deep connection to the domain experts way of thinking
      • The abstractions are true business principles
    • Continuous learning
      • Domains that seem less technically daunting can be deceiving, we don't realize how much we don't know !
    • Knowledge rich design
      • Business activities and rules are as central to a domain as are the entities involved
      • Knowledge crunching yields models that reflect this kind of insight
    • Deep models
      • As we come to understand the domain, we usually discard superficial model elements
      • Subtle abstractions emerge that pierce into the heart of the matter
      • Models of utility call for sophistication both in the domain and in the modelling technique
      • Knowledge crunching is an exploration and you cant know where you will end up

Thursday, 4 June 2020

Designing an engineering Jugaad




So one fine day we came to know that that the underground water tank is almost empty ! Although we have a fully automated electric pump system which sucks water from underground tank and takes it to water tank on 3rd floor, it acts on water level signal from upper tank, while lower tank is ... "assumed to be filled optimally". But now we came to know that hmm the main input water supply is "not enough" or maybe the input water has not being coming daily ! Yes in undeveloped countries water does not come continuously like electricity. It will come for half hour to two or so hours at any "random time" !

Now the solution to almost empty underground water tank is to use electric motor on main input water supply and fill the underground tank to optimal level. This we need to do not daily but for 2-3 days and after that maybe never based on assumption that the input water supply resumes its mysterious random frequency and flow again !

The problem now is : "How to know when the input water came?". Hmm this needs some sort of water detector. We can purchase some fancy water flow meter and attach it in series to input pipe and measure the signal and attach it to a fancy system like bell. But oh... wait we - the country - is facing a LOCKDOWN ! Hmm so Corona has its name in this story also ! Anyways so the bottom line is : a solution is needed fast and has to be homegrown - cant get any supply from outside.

Can we do without an input water detector ? Yes but then we need to be constantly vigilant of what is happening outside house, we might miss the water tap noise, we might hear it late and hence not solving the water problem. Hmm so looks like we need an engineering solution.

We had a door bell, and some wire. Awesome what if ... a water filled jar can be used to trigger the bell and problem solved ! So after some fidgeting, ripping open some wires and applying tape and bending the two open wire tips and putting an old pencil cell in the old door bell, I experimented with it ... and it worked. As soon as both ends of wire are in water the bell rings... cool. Now a small jar which can collect water from a tap on the water input, as the jar fills the wires conduct and bell rings. Great, one problem solved.

Now when we know what fresh water has come via the bell, which can not be missed as it is loud and catches attention rather quickly. One has to empty the jar which has the alarm wires. Then do some turning and twisting of valves and then apply motor on fresh input water to the underground tank. So far so good. But what happens if input fresh water goes - you see it wont last more than 2 hours or half an hour generally ? In that case motor runs without water and ... this will damage the motor. So problem two : "How to know when the input water has stopped ?"

Hmm to know that water stopped, can we have some way to ring the bell when water stops ? One thing which instantly comes to mind is make a NOR gate and use it to convert an OFF signal into an ON signal which can then ring the bell. Well one may ask how to get a signal when water stops ? One way can be put some conductor which are always immersed in water and when water goes off, then these conductors will STOP conduction or will be in OFF state. Sounds good but I did not want to make this complex, so instead of an electronic NOT gate - I thought why not have a mechanical NOT ? Another disadvantage of electronic NOT would be a voltage would be applied to water and I might have to worry about hydrolysis due to charge !

So how will a mechanical NOT work ? After some pondering I realised it would need some sort of mechanical toggle, when water stops or goes OFF then that should get converted into an ON signal which can then drag a wire which has two open conductors, into a water container.

Hmm sounds reasonable, but how to create the mechanical toggle - upon pondering i realised that a water container with a hole at bottom will empty itself after input water is off. Main property of such a setup is that the weight of this container will decrease drastically after input water supply is off. Hmm so all we need is a sort of pulley system with a heavy but not too heavy weight on the other end. When water supply is on, the container with hole has enough weight to not get pulled up by the weight on other side but when its empty then other side's weight is enough to pull hole container up. This is a mechanical NOT gate ! Gravity is magic :) !

Now the setup is simple - water supply stops, Water leaks from the hole at bottom, its weight decreases, the other side of pulley has a weight and a wire attached to it and gets pulled down. This puts the conducting wire into water and voila the bell rings !!!



Fig. 1

In figure 1 above one can see the small container with a pair of wire going inside. This is what gets pulled in when water supply stops. One can also see the wire connecting to the alarm bell. Also there is a weight (some old metal pipe i used). To solve problem 1 - water on detection - the same small container can also be used to collect water and it will ring the alarm to detect water supply start !


Now see the figure 2 below, this is the mechanical NOT gate aka pulley :


Fig. 2

I had some old pipe, so I made two notches in it for the thread to run along for stability and less friction. Used an old plastic bottle  (one on left) and attached the thread to it. It also has a hole in bottom. See the water is falling in from top. When the water stops is empties itself. Now if you look at thread carefully - on left is plastic bottle with hole and on right is a counter weight, which falls down when left bottle is empty. And when it falls it drags the wire into plastic container two as seen in figure 1.

I measured the timing, and it takes about 3 minutes from water input stopping to alarm ringing.

and that how one builds a water on and off detector with basic home items !

Friday, 7 February 2020

OOD - Online Book Reader

Untitled1

OOD for Online book reader

Requirements

  • User should be able to search in a library of books
  • Choose a book
  • Read a book
  • Turn pages of book

The code here will be pythonic version of the solution in CTCI here :

https://github.com/careercup/CtCI-6th-Edition/tree/master/Java/Ch%2007.%20Object-Oriented%20Design/Q7_05_Online_Book_Reader

Actors and use cases

  • User
    • Browses a library of books
    • Chooses a book
    • Book page is displayed to user
    • User turns page
    • User chooses new book to open

Classes and their responsibilities

  • Book
    • Represents a book and its content
  • User
    • Represents the user
  • Library
    • This will hold all the books
  • OnlineReaderSystem
    • This is composed of library, a user manager and a display unit
    • This also sets an active user and an active book
  • Display
    • Responsible for displaying the book
    • When user chooses a page that should be shown, like swipes to next page or back
  • UserManager
    • This takes care of addin and removing users from the system

online_reader_cd.png

In [45]:
class OnlineReaderSystem(object):
    def __init__(self):
        self._library = Library()
        self._user_manager = UserManager()
        self._display = Display()
        
        self._active_book = None
        self._active_user = None
        
    def get_library(self) -> Library:
        return self._library
    
    def get_user_manager(self) -> UserManager:
        return self._user_manager
    
    def get_display(self) -> Display:
        return self._display
    
    @property
    def active_book(self) -> Book:
        return self._active_book
    
    @active_book.setter
    def active_book(self, book: Book):
        self._active_book = book
        self._display.display_book(book)
        
    @property
    def active_user(self) -> User:
        return self._active_user
    
    @active_user.setter
    def active_user(self, user: User):
        self._active_user = user
        self._display.display_user(user)
        

class Library(object):
    def __init__(self):
        self.books = {}
        
    def add_book(self, book: Book):
        self.books[book.id] = book
        
    def remove_book(self, book: Book):
        self.remove_book(book.id)
        
    def remove_book(self, id_: int):
        del self.books[id_]
        
    def find_book(self, id_: int) -> Book:
        if id_ in self.books:
            return self.books[id_]
        else:
            return None
        

class UserManager(object):
    def __init__(self):
        self.users = {}
    
    def add_user(self, user: User):
        self.users[user.id] = user
    
    def remove_user(self, user: User):
        self.remove_user(user.id)
    
    def remove_user(self, id_: int):
        del self.users[id_]
        
    def find_user(self, id_) -> User:
        return self.users[id_]
    

class Display(object):
    def __init__(self):
        self._book = None
        self._user = None
        self._page_number = -1
        
    def display_user(self, user: User):
        self._user = user
        self._refresh_username()
    
    def display_book(self, book: Book):
        self._book = book
        
        self._refresh_title()
        self._refresh_details()
        self._refresh_page()
        
    def turn_page_forward(self):
        self._page_number = self._page_number + 1
        self._refresh_page()
        
    def turn_page_backward(self):
        self._page_number = self._page_number - 1
        self._refresh_page()
        
    # private methods
    def _refresh_username(self):
        print('The username update to : %s' % self._user.name)
        
    def _refresh_title(self):
        print('The title of book updated to : %s' % self._book.title)
        
    def _refresh_details(self):
        print('The details of book updated to : %s' % self._book.details)
        
    def _refresh_page(self):
        print('Refreshed the current page number : %d' % self._page_number)
        

class Book(object):
    def __init__(self, id_: int, title: str , details: str):
        self.id = id_
        self.title = title
        self.details = details
        

class User(object):
    def __init__(self, id_: int, name: str, account_type: int, details: str):
        self.id = id_
        self.name = name
        self.account_type = account_type
        self.details = details
        
    # other user relate methods
    def renew_membership(self):
        pass
    
    
In [46]:
class OnlineReaderSystemTestCLI(object):
    def __init__(self):
        self.reader = OnlineReaderSystem()
        
    def start(self):
        # add some books to library
        library = self.reader.get_library()
        
        rmy = Book(1001, 'Ramayana', 'Story of how Raama came back')
        mbt = Book(2002, 'Mahaabhaarata', 'Story of Pandavas and Kauravas')
        library.add_book(rmy)
        library.add_book(mbt)
        
        # add some users to user manager
        user_manager = self.reader.get_user_manager()
        
        ram = User(1, 'Rameshvara', 0 , 'Premium User')
        lak = User(2, 'Lakshmana', 1, 'Standard User')
        user_manager.add_user(ram)
        user_manager.add_user(lak)
        
        # now lets set a book and user in the system
        self.reader.active_user = ram
        self.reader.active_book = rmy
        
        # now lets flip the pages
        display = self.reader.get_display()
        display.turn_page_forward()
        display.turn_page_forward()
        display.turn_page_backward()
        
In [47]:
cli = OnlineReaderSystemTestCLI()
cli.start()
The username update to : Rameshvara
The title of book updated to : Ramayana
The details of book updated to : Story of how Raama came back
Refreshed the current page number : -1
Refreshed the current page number : 0
Refreshed the current page number : 1
Refreshed the current page number : 0