npm

This package has been deprecated

Author message:

not the lib you are looking for. dalssoft @ gmail

grounds

1.0.2 • Public • Published

grounds

Uniform, auditable and secure use case javascript library. Influenced by Clean Architecture and Trailblazer

Installing

$ npm install grounds

Using

Check the complete examples here.

usecases/addOrUpdateItem.js:

const { Ok, Err, usecase, step, ifElse } = require('../../../src/grounds')
const dependency = {
    ItemRepository: require('../repositories/ItemRepository').ItemRepository,
    ...
}
 
const addOrUpdateItem = (injection) =>
 
    usecase('Add or Update an Item on a to-do List', {
 
        // Input/Request type validation 
        request: { listId: Number, item: Object },
 
        // Authorization Audit  
        authorize: (user) => user.isAdmin ? Ok() : Err(),
 
        // Dependency Injection control
        setup: (ctx) => ctx.di = Object.assign({}, dependency, injection),
        
        // Step audit and description
        'Check if the Item is valid': step((ctx) => {
            ...
            return item.validate() // Ok or Error
        }),
 
        'Check if the List exists': step(async (ctx) => {
            ...
            return Ok()
        }),
 
        // Conditional step
        'Add or Update the Item': ifElse({
 
            'If the Item exists': step(async (ctx) => {
                ...
                return Ok(newItem)
            }),
 
            'Then: Add a new Item to the List': step(async (ctx) => {
                ...
                return await itemRepo.save(item) // Ok or Error
            }),
 
            'Else: Update Item on the List': step(async (ctx) => {
                ...
                return await itemRepo.save(item) // Ok or Error
            })
        })
    })

controler/addOrUpdateItem.js:

app.put('/items/:item', function (req, res) {
    const request = req.params
    const user = { name: 'John', id: '923b8b9a', isAdmin: true } // from session
 
    const uc = addOrUpdateItem()
    uc.authorize(user)
    const ret = await uc.run(request)
    res.send(ret)
})

uc.doc():

{
  type: 'use case',
  description: 'Add or Update an Item on a to-do List',
  request: { listId: Number, item: Object },
  steps: [
    { type: 'step', description: 'Check if the Item is valid', steps: null },
    { type: 'step', description: 'Check if the List exists', steps: null },
    { 
        type: 'if else',
        if: { type: 'step', description: 'If the Item exists', steps: null },
        then: { type: 'step', description: 'Then: Add a new Item to the List', steps: null },
        else: { type: 'step', description: 'Else: Update Item on the List', steps: null }
    }
  ]
}

uc.auditTrail:

{
    type: 'use case',
    description: 'Add or Update an Item on a to-do List',
    transactionId: '9985fb70-f56d-466a-b466-e200d1d4848c',
    user: { name: 'John', id: '923b8b9a', isAdmin: true },
    authorized: true,
    return: {
        Ok: { item: { id: 100, name: 'Do not forget this', position: 9 } }
    },
    steps: [
        { type: 'step', description: 'Check if the Item is valid', return: {} },
        { type: 'step', description: 'Check if the List exists', return: {} },
        {
            type: 'if else', 
            description: 'Add or Update the Item',
            returnIf: { Ok: true },
            returnThen: {}
        }
    ]
}

Motivations

Maintainability

"Programs must be written for people to read, and only incidentally for machines to execute" - Harold Abelson, Structure and Interpretation of Computer Programs

Understanding what a software is doing from a business perspective is a must in order to be able to change it quickly and in a sustainable way.

Metadata for system intent

It should be easy to retrieve a system's metadata for all its use cases and steps. This info could be used to leverage innovative interfaces (ex: dynamic admin pages, use case documentations, etc), helping narrow the gap between developers, testers and product managers.

Auditable and Secure

It should be easy to have enterprise grade features even for simple applications. Authorization and auditing, for instance, should be available out of the box. Not using should be opt-in.

Use Case

What is it?

A Use Case reflects a single action exposed by the Domain to the end user. Ex: Reopen Ticket, Reply Message, Add User

Internaly a Use Case control the interaction between Entities, Repositories (infrastructure) and other Domain components.

It should:

  • Be modeled around business
  • Be reusable
  • Be testable / Have clear acceptance criteria
  • Help identify right architecture
  • Ubiquitous language

"Use cases orchestrate the flow of data to and from the entities, and direct those entities to use their Critical Business Rules to achieve the goals of the use case." - Clean Architecture book

Best pratices

  • Keep it simple by telling stories
  • Understand the big picture
  • Focus on value
  • Build the use case in steps

Architecture:

  • Implement business flows using Use Cases.

    Ex: Reply Message use case interacts with Message, Ticket, User and others entities in order to reply a message for a user

  • Split the flows in smaller steps

  • Avoid implement validations using Use Cases. Prefer Entities for validations

  • Access Use Cases from outside the Domain

    Use cases are the "entry points" for the Domain layer, so it is the only accessible layer from outside the Domain.

  • Don't access any other sublayer which belongs to Domain layer (Entities, etc) apart Use Case from outside Domain

  • Name the Use Case folder, file and its steps as an action (verb).

    Ex: OpenTicket.js, ReplyMessage.js, AddUser.js

    Use Cases are implemented as command patterns.

References:

  • Clean Architecture book link
  • Use Case 2.0 link
  • Use Case diagram link
  • Service Layer link

To Do

  • Base - Run a use case
  • Use Case Error - Ok or Error results for a use case (Rust inspired)
  • Steps - Enable multiple steps for a use case
  • Nested Steps - Enable multiple steps for a parent step
  • Nested Steps - multiple files - Enable multiple steps in diferent files for a parent step
  • Use usecase as a step
  • Doc Step - Get description and structure from use case and its steps
  • Request - Be able to describe and validate the use case request object
  • Response - Be able to describe and validate the use case response object
  • Dependency Injection (removed)
  • ctx var - Share context between Steps
  • Conditional Steps - Enable a If/Else constructor for steps
  • Authorization - Be able to authorize the execution of a use case and its steps
  • Audit - Be able to track use case runtime information
  • Audit - Timing - Be able to track use case and its steps execution time
  • Async / MQ - Multiple Rounds - Be able to partially execute a use case and continue (when a MQ is necessary, for instance)
  • transaction ID - A ID to track execution between steps
  • session ID - A ID to track execution between use cases
  • Deal with exceptions
  • Deal with no default results (Ok/Err)
  • Deal with async / await steps
  • Use case examples
  • Doc - Documentation and samples for each feature

Contribute

Come with us to make an awesome Grounds.

Now, if you do not have technical knowledge and also have intend to help us, do not feel shy, click here to open an issue and collaborate their ideas, the contribution may be a criticism or a compliment (why not?)

We have some conventions to contribute to the Grounds project, see more information in our CONTRIBUTING.md. So please, read this before send to us a pull requests.

License

Grounds is released under the MIT license.

Package Sidebar

Install

npm i grounds

Weekly Downloads

0

Version

1.0.2

License

MIT

Unpacked Size

644 kB

Total Files

28

Last publish

Collaborators

  • dalssoft