Bingo for meetings–obsolete–re-reading requirements- part 7

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub

(Now the actual blog post for Bingo Meetings project)

Last time we have to implement the requirement:

Meeting Obsolete:
The meeting is available for 35 minutes. After that, meeting is not available anymore.

We did so for the 35 minutes. But we did not for the last sentence – meeting is not available anymore. There are 2 points here: of design ( do not retrieve meeting ) and enforcing that no participant can write to the meeting.

So we modify the functions   AddParticipant, CheckCardByParticipant  to raise an exception if the meeting is obsolete .( As a side effect of identifying the functions that make actions in the opposite of functions that just reports, I think about structuring code in CQRS form )

Now for TypeScript we have 2 options :

  1. Construct a class that inherits from Error
  2. Modify the response type of those function to a combined type of result and error

For the first one , we should take care of TypeScript syntax of creating errors: See https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html  and https://github.com/Microsoft/TypeScript-wiki/blob/master/Breaking-Changes.md#extending-built-ins-like-error-array-and-map-may-no-longer-work

class CustomError extends Error {

constructor(message?: string) {

super(message);

// ‘Error’ breaks prototype chain here

Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain

}

}

For the second , we could do ourselves or use a npm package such as https://github.com/gDelgado14/neverthrow

I decide to go to the second. I have too many times use the first thing in C# – it is time to have something new. Anyway, this is the code now

    import { ok, err, Result } from 'neverthrow';
//code
    public CheckCardByParticipant(c: Cards , p:Participant): Result<Meeting,Error>{
        //TODO: verify participant is added first or add
        //TODO: verify card is added first
        if(this.IsObsolete()){
            return err(new Error(`cannot check card to the obsolete meeting ${this.Id}`));
        }
        c.CheckMe(p);
        return ok(this);
    }
//code
    public AddParticipant(p:Participant ): Result<number,Error>{
        if(this.IsObsolete()){
            return err(new Error(`cannot add participant to the obsolete meeting ${this.Id}`));
        }

        this.Participants.push(p);
        return ok(this.Participants.length);
    }

and those are the tests

        const mf=new MeetingsFactory();

        const m1=mf.CreateMeeting("andrei","first meeting");
        const now = Date.now();
        const spy = jest.spyOn(Date,'now');
        spy.mockImplementation(()=>{
          console.log('calling DateTime Now');
          return now + 36 * 60* 1000;
        } );
        expect(m1.IsObsolete()).toBe(true);
        const p=new Participant();
        p.Id=70;
        p.Name ="alexandru";
        const res= m1.AddParticipant(p);
        expect(res.isOk()).toBe(false);
        spy.mockRestore();

Bingo for meetings–obsolete–part 6

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)

NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub

(Now the actual blog post for Bingo Meetings project)


The requirement says:

Meeting Obsolete:
The meeting is available for 35 minutes. After that, meeting is not available anymore.

How we can implement this ? Several solutions:

  1. Make the meeting know about this ( and avoiding https://martinfowler.com/bliki/AnemicDomainModel.html )
  2. Make a decorator class for this https://en.wikipedia.org/wiki/Decorator_pattern
  3. Make a mixin in TypeScript https://www.typescriptlang.org/docs/handbook/mixins.html

 

I decide to KISS (https://en.wikipedia.org/wiki/KISS_principle ) and take the first point. We implement an Obsolete function. Remains who is responsible of the site to call it.

Now comes other question: When the meeting starts  ?I consider ( for the sake of easy path) that a meeting starts when it is created . So the code is like this

export default class Meeting{

    constructor(){
        this.Participants = [];        
        this.Cards = [];
        this.startedMeeting = Date.now();
    }
    public static  MaxTime=35 * 60 * 1000;
    // other code here
    public IsObsolete(): boolean{
        return (this.PassedTimeFromStart() > Meeting.MaxTime); //35 minutes
    }
    public PassedTimeFromStart():number{
        let dtNow =  Date.now();
        console.log(dtNow);
        return (dtNow - this.startedMeeting );
    }

 

 

Now the problem arises when testing code. It is very easy to say that a meeting is not obsolete when just created. However , I do not want to wait for 35minutes + 1 second in order for a meeting to become obsolete and the test to be successful( see
//TODO: wait 35 minutes + 1 second

below).


import  MeetingsFactory from '../MeetingsFactory';
import Meeting from '../meeting';
describe('Meeting Obsolete', () => {
    it('meeting should not be obsolete after creation', () => {
        const mf=new MeetingsFactory();
        const m1=mf.CreateMeeting("andrei","first meeting");
        expect(m1.IsObsolete()).toBe(false);
        
        
  
      })
      it('meeting should  be obsolete after 35 minutes', () => {
        const mf=new MeetingsFactory();

        const m1=mf.CreateMeeting("andrei","first meeting");
        //TODO: wait 35 minutes + 1 second
        expect(m1.IsObsolete()).toBe(true);
        
  
      })
  })
  

One possible resolution is https://ayende.com/blog/3408/dealing-with-time-in-tests . However, the problem is so common that here must be include in the test framework ( in this case, jest). And , indeed, it is a way: spyon. So the code is modified accordingly :

it('meeting should  be obsolete after 35 minutes', () => {
        const mf=new MeetingsFactory();

        const m1=mf.CreateMeeting("andrei","first meeting");
        const now = Date.now();
        const spy = jest.spyOn(Date,'now');
        spy.mockImplementation(()=>{
          console.log('calling DateTime Now');
          return now + 36 * 60* 1000;
        } );
        expect(m1.IsObsolete()).toBe(true);
        //spy.mockClear();        
        spy.mockRestore();
        expect(m1.IsObsolete()).toBe(false);
        
  
      })

The testing code now assumes that he knows inner working of the code – and the test will fail if we modify the call of Date.now().
So I think that https://ayende.com/blog/3408/dealing-with-time-in-tests is far superior.

Bingo for meetings–working at score-part 5

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)

NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub

(Now the actual blog post for Bingo Meetings project)


The next requirement is saying ( https://github.com/alexandru360/PresentationBingoCards/projects/1#card-24165817 )

Checking cards:
A total score will be displayed when checking / unchecking

There are 2 things very clear:

  1. The name of the user story is not reflecting the content
  2. It should not be just the total score, but also should be the percentage of the bingo cards checked from the total number of cards. It is not so difficult to have the total number of cards, so let’s add this.

 

We have put this code:

 

public TotalNumberOfCardsChecked():number{
        return this.Cards.filter(it=>it.IsChecked()).length ;
    }
    

 

And we put test

it('number of cards checked', () => {
        const mf=new MeetingsFactory();
        const m1=mf.CreateMeeting("andrei","first meeting");
        console.log(m1.Cards.length);
        
        expect(m1.TotalNumberOfCardsChecked()).toBe(0);
        m1.CheckCardByParticipant(m1.Cards[0], m1.Participants[0]);    
        expect(m1.TotalNumberOfCardsChecked()).toBe(1);
        
        
  
      })

 

We see that for TotalNumberOfCardsChecked and AllUnchecked we have the same code

public AllUnchecked(): boolean{
        return (this.Cards.filter(it=>it.IsChecked()).length === 0);
    }
    //other code
public TotalNumberOfCardsChecked():number{
        return this.Cards.filter(it=>it.IsChecked()).length ;
    }

and because we hate copy paste we refactor and re-test


So we refactor a bit .


public AllUnchecked(): boolean{
        return (this.TotalNumberOfCardsChecked() === 0);
    }

And because we have tests, that means we are pretty confident of what are we doing

Also, we said that we have to calculate the total number of checked cards. This is not so difficult, and it alleviates the Law of Dots /Demeter (https://haacked.com/archive/2009/07/14/law-of-demeter-dot-counting.aspx)


public TotalNumberOfCards():number{
        return this.Cards.length;
    }

The consequence ? To maintain code coverage, we should add another line of test:


expect(m1.TotalNumberOfCards()).toBe(Cards.DefaultCards().length);
 

Also, because the requirement says to display, and we are not yet to the GUI, I have put a new note that says

Design:
– [ ] display total number of cards checked or percentage ( use TotalNumberOfCardsChecked and/or TotalNumberOfCards)

Bingo for meetings– working at sharing meeting with others–part 4

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub

(Now the actual blog post for Bingo Meetings project)

Other use case for Bingo Meetings was Share meeting bingo(https://github.com/alexandru360/PresentationBingoCards/projects/1#card-24165765)

Share Meeting Bingo:

As a User, I can receive the meeting Id( url) . When going to this url , I can ( optionally) enter my name and check cards.

So how to implement this  ? A Meeting contains an array of Cards and a array of Participants. How a Participant can check cards ?

There are several solutions for this:

  1. The Participant can have an Id of the meeting, is going to some form of database( even in memory , like a singleton collection of Meetings), retrieve the meeting, retrieve the cards, check the card
  2. The participant raise an event ( PleaseCheckThisCardForMe) , the meeting listens and checks the meeting
  3. The participant have a real reference of the cards and checks the cards
  4. The meeting has a  CheckCardByParticipant that someone can call ( leaving the responsibility later  – maybe on API )

We ( me and Alexandru Badita we have choosed the latest solution. So we came with the following :


public CheckCardByParticipant(c: Cards , p:Participant){
        //TODO: verify participant is added first or add
        //TODO: verify card is added first
        c.CheckMe(p);
    }

and a test


import  MeetingsFactory from '../MeetingsFactory';
import Meeting from '../meeting';
describe('Check  card basic', () => {
    it('card should be checked', () => {
        const mf=new MeetingsFactory();
        const m1=mf.CreateMeeting("andrei","first meeting");
        console.log(m1.Cards.length);
        
        expect(m1.AllUnchecked()).toBe(true);
        m1.CheckCardByParticipant(m1.Cards[0], m1.Participants[0]);    
        expect(m1.AllUnchecked()).toBe(false);
        expect(m1.IsCardCheckedByParticipant(m1.Cards[0], m1.Participants[0])).toBe(true);
        
        
  
      })
    
  })
  

Obviously, from TODO, we have to put more code and more tests – but for the moment we think that nobody will want to break our application on purpose….

Bingo for meetings – part 3 – finalizing the “Create Meeting” scenario

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)

NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub

(Now the actual blog post for Bingo Meetings project)


In the “Create Meeting” scenario it was something that we have passed : ” application generates an unique Id that I can access the bingo cards ( state : not checked) for that meeting ” ( see https://github.com/alexandru360/PresentationBingoCards/projects/1#card-24165690 )
How we can emulate this ? Obviously, the meeting starts with a set of cards – but how about participants ? Do they have the same set of cards and check them ( bingo ) ?

There are some possible things to be programmed here:

1. The meeting have the unique set of cards and the dictionary of .

2. Every participant , when joining the meeting, have a copy ( by reference ) of the meeting cards and an array to see what is checked

3. Every card keep an array of participants that shows what participant have checked the card.

Guess what is easiear to implement ?

However, we have put a function on the meeting

public AllUnchecked(): boolean{
        return (this.Cards.filter(it=>it.IsChecked()).length === 0);
    }

and a test to ensure that, when creating a meeting, the function returns false.

So now the first scenario is done !

( On a personal note, I see that yarn is better than npm )

Bingo for meetings–part 2–working at tests

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)

NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub

(Now the actual blog post for Bingo Meetings project)


So now because we have created the objects and a function to create meetings, we do create some tests. We decided to work with JEST.

Steps:

  1. We read many tutorials (https://medium.com/@mtiller/debugging-with-typescript-jest-ts-jest-and-visual-studio-code-ef9ca8644132 , https://rjzaworski.com/2016/12/testing-typescript-with-jest , https://github.com/facebook/jest/tree/master/examples/typescript , https://amenallah.com/node-js-typescript-jest-starter/ , https://basarat.gitbooks.io/typescript/docs/testing/jest.html , https://dev.to/muhajirdev/unit-testing-with-typescript-and-jest-2gln )
  2. We solve many errors  ( forgetting put “ export default class “ , “ jest unexpected token import “ ,  jest.config.json  as opposed to jest.config.js
  3. Read jest expect documentation from https://jestjs.io/docs/en/expect.html#not
  4. We finally wrote 2 tests in order to verify meeting creation and run with npm test

 

import MeetingsFactory from '../MeetingsFactory';

import Meeting from '../meeting';

describe('Meetings creation', () => {

it('a meeting should have been created properly', () => {

const mf=new MeetingsFactory();

const m1=mf.CreateMeeting("andrei","first meeting");

expect(m1.Name).toBe("first meeting");

expect(m1.Participants.length).toBe(1);

expect(m1.Participants[0].Name).toBe("andrei");

})

it('two meeting have different ids', () => {

const mf=new MeetingsFactory();

const m1=mf.CreateMeeting("andrei","first meeting");

const m2=mf.CreateMeeting("andrei","first meeting");

expect(m1.Id).not.toBe(m2.Id);

})

})

 

And with this we just verify first use case

Create Meeting Bingo:

As a user, I want to create a new meeting bingo: I use an username and meeting name and the application generates an unique Id that I can access the bingo cards ( state :  not checked) for that meeting

 

And not even the whole(  we do not have the cards , not the state for the cards!)

New project: Bingo for meetings–part 1

Bingo is a small project, written in TypeScript , and developed with Alexandru Badita in launch break (one hour - more or less). You can find sources at https://github.com/alexandru360/PresentationBingoCards/ . Those are my blog posts for Bingo : ( scroll below for the post)
NrLink
1Create meeting
2Create Tests
3Finalize Create meeting
4Sharing meeting
5Keep Score
6Add obsolete
7Finalizing obsolete
8End meeting
9Dockerize tests
10Azure CI tests
11Yarn workspaces
12CLI
13Intermezzo - CLI improvements
14typescript compile run with node
15NestJS ,swagger and create a meeting
16Finalizing API
17Intermezzo - jest vs jasmine error
18Refactor WebAPI and test service
19Heroku Deploy NestJs
20Angular
21Deploy Angular to GitHub

(Now the actual blog post for Bingo Meetings project)

I have decided to start a new project. The name is “Bingo for meetings”. What it does: Every time in a meeting that a participant hears a phrase (like “ Hi, can you hear me?” or “ can everyone see my screen?” or others …)  he can check one of the cards. In the final you can see for the meeting how many cards you have checked.

I am doing the project with Alexandru Badita (http://alexandru360.blogspot.com/) .  We agreed to be in ONLY in TypeScript .

We are doing at Starbucks the pair programming and exchange ideas. Total time: 1 hour

In the first meeting we have  put the specifications at https://github.com/alexandru360/PresentationBingoCards/projects/1

Create Meeting Bingo:

As a user, I want to create a new meeting bingo: I use an username and meeting name and the application generates an unique Id that I can access the bingo cards ( state :  not checked) for that meeting

Share Meeting Bingo:

As a User, I can receive the meeting Id( url) . When going to this url , I can ( optionally) enter my name and check cards

Checking cards:
A total score will be displayed when checking / unchecking

EndMeeting:
The score of how many cards/ what cards were checked will be available 1 hour and 5 minutes

Meeting Obsolete:
The meeting is available for 35 minutes. After that, meeting is not available anymore.

Also, we have created the classes Meeting, Participant,  Also, we have created a MeetingsFactory that can create a Meeting.

You can fist the result of our code at https://github.com/alexandru360/PresentationBingoCards/releases/tag/firstMeeting 

.

My Visual Studio Code Extensions

I have many extensions on Visual Studio Code. The most impressive are Docker (ms-azuretools.vscode-docker , ms-vscode-remote.remote-containers ) , export extensions to a gist (Shan.code-settings-sync ) and various languages extensions ( powershell, csharp).

 

Anyway, this is the whole list:

 

  • christian-kohler.npm-intellisense
  • CoenraadS.bracket-pair-colorizer
  • dbaeumer.vscode-eslint
  • donjayamanne.githistory
  • DotJoshJohnson.xml
  • eamodio.gitlens
  • eg2.tslint
  • eg2.vscode-npm-script
  • esbenp.prettier-vscode
  • formulahendry.auto-close-tag
  • formulahendry.auto-rename-tag
  • hoovercj.vscode-dimmer
  • humao.rest-client
  • johnpapa.vscode-peacock
  • karigari.chat
  • ms-azure-devops.azure-pipelines
  • ms-azuretools.vscode-azurefunctions
  • ms-azuretools.vscode-docker
  • ms-mssql.mssql
  • ms-vscode-remote.remote-containers
  • ms-vscode-remote.remote-ssh
  • ms-vscode-remote.remote-ssh-edit
  • ms-vscode-remote.remote-ssh-explorer
  • ms-vscode-remote.remote-wsl
  • ms-vscode-remote.vscode-remote-extensionpack
  • ms-vscode.azure-account
  • ms-vscode.csharp
  • ms-vscode.powershell
  • ms-vscode.vs-keybindings
  • ms-vsliveshare.vsliveshare
  • ms-vsliveshare.vsliveshare-audio
  • ms-vsliveshare.vsliveshare-pack
  • ms-vsts.team
  • msjsdiag.debugger-for-chrome
  • oderwat.indent-rainbow
  • quicktype.quicktype
  • redhat.vscode-yaml
  • sdras.night-owl
  • Shan.code-settings-sync
  • TzachOvadia.todo-list
  • vchristian-kohler.npm-intellisense
  • CoenraadS.bracket-pair-colorizer
  • dbaeumer.vscode-eslint
  • donjayamanne.githistory
  • DotJoshJohnson.xml
  • eamodio.gitlens
  • eg2.tslint
  • eg2.vscode-npm-script
  • esbenp.prettier-vscode
  • formulahendry.auto-close-tag
  • formulahendry.auto-rename-tag
  • hoovercj.vscode-dimmer
  • humao.rest-client
  • johnpapa.vscode-peacock
  • karigari.chat
  • ms-azure-devops.azure-pipelines
  • ms-azuretools.vscode-azurefunctions
  • ms-azuretools.vscode-docker
  • ms-mssql.mssql
  • ms-vscode-remote.remote-containers
  • ms-vscode-remote.remote-ssh
  • ms-vscode-remote.remote-ssh-edit
  • ms-vscode-remote.remote-ssh-explorer
  • ms-vscode-remote.remote-wsl
  • ms-vscode-remote.vscode-remote-extensionpack
  • ms-vscode.azure-account
  • ms-vscode.csharp
  • ms-vscode.powershell
  • ms-vscode.vs-keybindings
  • ms-vsliveshare.vsliveshare
  • ms-vsliveshare.vsliveshare-audio
  • ms-vsliveshare.vsliveshare-pack
  • ms-vsts.team
  • msjsdiag.debugger-for-chrome
  • oderwat.indent-rainbow
  • quicktype.quicktype
  • redhat.vscode-yaml
  • sdras.night-owl
  • Shan.code-settings-sync
  • TzachOvadia.todo-list
  • vscode-icons-team.vscode-icons
  • wayou.vscode-todo-highlight
  • zhouronghui.propertylist
  • scode-icons-team.vscode-icons
  • wayou.vscode-todo-highlight
  • zhouronghui.propertylist

 

You can find the list here: https://gist.github.com/ignatandrei/9edba23cc2ca5dc5e0971432c709fc9e

Of course, I should review each one. However, maybe in the tools list  I will explain each one this year  http://msprogrammer.serviciipeweb.ro/programmer-tools/

What are your extensions?

Andrei Ignat weekly software news(mostly .NET)

* indicates required

Please select all the ways you would like to hear from me:

You can unsubscribe at any time by clicking the link in the footer of our emails. For information about our privacy practices, please visit our website.

We use Mailchimp as our marketing platform. By clicking below to subscribe, you acknowledge that your information will be transferred to Mailchimp for processing. Learn more about Mailchimp's privacy practices here.