Skip to content
This repository has been archived by the owner on Aug 16, 2021. It is now read-only.

An attempt towards non-procedural programming #13

Open
AmitKumarDas opened this issue Dec 23, 2015 · 0 comments
Open

An attempt towards non-procedural programming #13

AmitKumarDas opened this issue Dec 23, 2015 · 0 comments
Assignees

Comments

@AmitKumarDas
Copy link

What will this lead to ?

  - no more nested if else conditions i.e. less cyclomatic complexity
  - code in object oriented way
  - compose your code naturally
  - highly cohesive code
  - loosely coupled code
  - build any feature in days
  - all concerns are abstracted
  - no more hard codings
  - no abuse/over-use of throwing exceptions
  - proper error handling
  - use of builder, template, decorator, compositional, callback patterns
  - feed stats for higher level objectives e.g. circuit breaker pattern

How to design ?

  - a theoretical design is implemented via code/pseudo logic
  - Initial sections talks about various scenarios of using this approach
  - later on, one can find the core implementation details
  - code/pseudo logic follows Java conventions w.r.t class & namespaces

Chapter 1

  • How about below syntax ? Is it SQL? Is it Java ?
  - select().from(t).where(row(t.a, t.b).eq(1, 2));
  - select().from(t).where(row(t.a, t.b).overlaps(date1, date2));
  - select().from(t).where(row(t.a, t.b).in(select(t2.x, t2.y)));
  - update(t).set(row(t.a, t.b), select(t2.x, t2.y).where(...));
  - insertInto(t, t.a, t.b).values(1, 2);

Chapter 2
A sample package that depends on DB, AMQP & core

  • Create Volume Code Style 1
  - executor.withChecks()
           .addEntry(POOL_PROPERTIES.POOL_ID, poolid)
           .addEntry(VOLUME_PROPERTIES.VOL_NAME, volname)
           .continueChecksOnError()
           .isPoolAvailable()
           .isUniqueVolume()

   # LOG all the entries in k:v pairs
   log.debug(executor.getentries())
   # will log all the PASSED checks
   log.debug(executor.getPassedChecks())

   # add to EVENTS
   buildCreateVolumeEvents(entries)

   if (executor.isChecksError())
   {
       log.error(executor.getCheckErrors())
       return
   }

   if (executor.isChecksFailed())
   {
       log.error(executor.getFailedChecks() + executor.getCheckMessages())
       return
   }

  buildCreateVolumeEvents(entries){
      event.add(VOLUME_EVENT_PROPERTIES.VOL_ID,
                        entries.get(VOLUME_PROPERTIES.VOL_ID))
      event.append(POOL_EVENT_PROPERTIES.VOL_ID,
                        entries.get(POOL_PROPERTIES.POOL_ID))
      event.append(executor.getPassedChecks())
      event.append(executor.getFailedChecks())
      event.append(executor.getCheckMessages())
      event.append(executor.getCheckErrors())
  }


  • Create Volume Code Style 2
  - if(executor.withChecks()
        .addEntry(POOL_PROPERTIES.POOL_ID, poolid)
        .addEntry(VOLUME_PROPERTIES.VOL_NAME, volname)
        .exitChecksOnError()
        .isPoolAvailable()
        .isUniqueVolume()
        .isChecksError())
   {
         ....
   } else {
         ....
   }
  • Create Volume Code Style 3
  - if(executor.withChecks()
        .addEntry(POOL_PROPERTIES.POOL_ID, poolid)
        .addEntry(VOLUME_PROPERTIES.VOL_NAME, volname)
        .exitChecksOnError()
        .isPoolAvailable()
        .isUniqueVolume()
        .isChecksSuccess())
   {
         onCreateVolCheckSuccess.execute()
   } else {
         onCreateVolCheckErr.execute()
   }
  • Create Volume Code Style 4
  - executor.withChecks()
        .addEntry(POOL_PROPERTIES.POOL_ID, poolid)
        .addEntry(VOLUME_PROPERTIES.VOL_NAME, volname)
        .exitChecksOnError()
        .isPoolAvailable()
        .isUniqueVolume()
        .onChecksError(onCreateVolCheckErr)
        .onChecksSuccess(onCreateVolCheckSuccess)
  • DR Code Style 1
  - if(executor.withChecks()
           .addEntry(DR_PROPERTIES.DR_ID, drid)
           .addEntry(DR_PROPERTIES.DR_NAME, drname)
           .addEntry(DR_PROPERTIES.DR_SCHEDULE, drschedule)
           .exitChecksOnError()
           .isPoolAvailable()
           .isDRNameUnique()
           .isDRScheduleValid()
   {
         ....
   } else {
         ....
   }

Chapter 3
A sample package that depends on DB, AMQP & core

  • Activate Migration Code Style 1
  - if(migrationCheckExecutor.withChecks()
           .addEntry(MIGRATION_PROPERTIES.ID, id)
           .addEntry(MIGRATION_PROPERTIES.NAME, name)
           .exitChecksOnError()
           .isPoolAvailable()
           .onChecksError(activateMigrationErrorHandler)
           .onChecksSuccess(activateMigrationSuccessHandler)
           .onActivationWarn(activateMigrationWarnHandler);
  • MigrationCheckExecutor.java (builder pattern)
    - extends StorageCheckExecutor
    - boolean isActivationWarn = false
    - public boolean isActivationWarn()
    - public executor onActivationWarn(StorageCheckCallback)
      - if isChecksPassed && isActivationWarn then execute the StorageCheckCallback
      - return this
  • StorageCheckExecutor.java (builder pattern)
    - entries = Map<ECStorageProperties, String>
    - boolean exitChecksOnError = true
    - public executor getEntries()
      - will return a clone of entries
    - public executor withChecks()
      - will create a new instance of entries
      - will return this
    - public executor addEntry()
      - will add a new entry to entries & return this
    - boolean isChecksError
      - will return not issuccess
    - boolean isChecksSuccess
      - will return true if there are no errors
    - boolean isChecksPassed
      - will return true if there all checks have passed
    - boolean isChecksFailed
      - will return true if at least one check has failed
    - getCheckErrors
      - will return the filtered entries that contain only check errors
    - getCheckMessages
      - will return the filtered entries that contain only check messages
    - getPassedChecks
      - will return the filtered entries that contain only the PASSED checks
    - getFailedChecks
      - will return the filtered entries that contain only the FAILED checks
    - continueChecksOnError
      - will continue executing check based methods even with previous errors
    - exitChecksOnError
      - default behavior
      - will not execute any check based methods if there were previous errors
    - public executor onChecksError(StorageCheckCallback)
      - if isError is true then execute the StorageCheckCallback
      - return this
    - public executor onChecksSuccess(StorageCheckCallback)
      - if isSuccess is true then execute the StorageCheckCallback
      - return this   
    - public executor onPassedChecks(StorageCheckCallback)
      - if isChecksPassed is true then execute the StorageCheckCallback
      - return this
    - public executor onFailedChecks(StorageCheckCallback)
      - if isChecksFailed is true then execute the StorageCheckCallback
      - return this   
    - public executor isPoolAvailable()
      - if exitonerror && iserror then return this
      - checkInst = new IsUniqueVolumeCheck()
      - checkInst.check(entries)
      - return this
    - public executor isUniqueVolume()
      - if exitonerror && iserror then return this
      - checkInst = new IsPoolAvailableCheck()
      - checkInst.check(entries)
      - return this

  • ECStorageCheck.java
    • all classes extending this class should be designed to be truthy checks
    • in other words all the check classes should set
      • PASSED for success &
      • FAILED for error or failure
    • e.g. have IsUniquePoolCheck than IsDuplicatePoolCheck
    • e.g. have IsPoolInMaintenance than IsPoolNotInMaintenance
    • above convention will help in better readability & lead to better maintenance
    • above convention will help in avoiding errors
    • entries is mutable
    - entries = Map<ECStorageProperties, String>
    - void precheck
    - abstract void docheck(entries)
    - void check (entries)
      - precheck()
      - docheck()
  • IsUniqueVolumeCheck.java
    - extends ECStorageCheck.java

    - void precheck()
       getentries().put(STORAGE_CHECK_STATUS.IS_UNIQUE_VOLUME_CHECK_STATUS,
                                  COMMON.FAILED)

    - void docheck(entries)
       if no entries then
         getentries().put(COMMON.STATUS, COMMON.ERROR)
         getentries().put(STORAGE_CHECK_ERR.IS_UNIQUE_VOLUME_CHECK_ERROR,
                                   COMMON.NONE + COMMON_ENTRIES)
         return      

       volname = entries.get(VOLUME_PROPERTIES.VOL_NAME)
       if no volname then
         getentries().put(COMMON.STATUS, COMMON.ERROR)
         getentries().put(STORAGE_CHECK_ERR.IS_UNIQUE_VOLUME_CHECK_ERROR, 
                                    COMMON.MISSING + COMMON_VOLUME + COMMON_NAME)
         return

       isVolInDB = queryVolAtDB(volname)
       if isVolInDB  then
         getentries().put(STORAGE_CHECK_MSG.IS_UNIQUE_VOLUME_CHECK_MSG, 
                                    VOLUME_MESSAGES.VOLUME_NAME_ALREADY_USED)
       else
         getentries().put(STORAGE_CHECK_STATUS.IS_UNIQUE_VOLUME_CHECK_STATUS,
                                   COMMON.PASSED)
         getentries().put(STORAGE_CHECK_MSG.IS_UNIQUE_VOLUME_CHECK_MSG, 
                                    VOLUME_MESSAGES.VOLUME_NAME_IS_NOT_USED)
  • IsPoolAvailableCheck.java
    - extends ECStorageCheck.java

    - void precheck()
       getentries().put(STORAGE_CHECK_STATUS.IS_POOL_AVAILABLE_CHECK_STATUS,
                                  COMMON.FAILED)

    - void docheck(entries)
       if no entries then
         getentries().put(COMMON.STATUS, COMMON.ERROR)
         getentries().put(STORAGE_CHECK_ERR.IS_POOL_AVAILABLE_CHECK_ERROR,
                                   COMMON.NONE + COMMON_ENTRIES)
         return      

       poolid = entries.get(POOL_PROPERTIES.POOL_ID)
       if no poolid then
         getentries().put(COMMON.STATUS, COMMON.ERROR)
         getentries().put(STORAGE_CHECK_ERR.IS_POOL_AVAILABLE_CHECK_ERROR, 
                                    COMMON.MISSING + COMMON_POOL + COMMON_ID)
         return

       isPoolAvailable = queryPoolAtDB(poolid)
       if isPoolAvailable then
         getentries().put(STORAGE_CHECK_MSG.IS_POOL_AVAILABLE_CHECK_MSG, 
                                    POOL_MESSAGES.POOL_IS_AVAILABLE)
         getentries().put(STORAGE_CHECK_STATUS.IS_POOL_AVAILABLE_CHECK_STATUS,
                                    COMMON.PASSED)
       else
         getentries().put(STORAGE_CHECK_MSG.IS_POOL_AVAILABLE_CHECK_MSG, 
                                    POOL_MESSAGES.POOL_IS_NOT_AVAILABLE)

Chapter 4
A sample core package that has no dependencies on other packages

  • ECStorageProperties.java
    - the base class/enum
  • CommonProperties.java
  - enum COMMON extends ECStorageProperties
      - NONE : 'no'
      - MISSING: 'missing'
      - VALUE: 'value'
      - ENTRIES: 'entries'
      - DATA: 'data'
      - INVALID: 'invalid'
      - STATUS: 'status'
      - ERROR: 'error'
      - SUCCESS: 'success'
      - PASSED: 'passed'
      - FAILED: 'failed'
      - POOL: 'pool',     
      - VOLUME: 'volume',
  • StorageCheckKeys.java
    - enum STORAGE_CHECK_ERR extends ECStorageProperties
      - IS_UNIQUE_POOL_CHECK_ERROR,
      - IS_POOL_IN_MAINTENANCE_CHECK_ERROR,
      - IS_POOL_AVAILABLE_CHECK_ERROR,
      - IS_UNIQUE_VOLUME_CHECK_ERROR,

    - enum STORAGE_CHECK_MSG extends ECStorageProperties
      - IS_UNIQUE_POOL_CHECK_MSG,
      - IS_POOL_IN_MAINTENANCE_CHECK_MSG,
      - IS_POOL_AVAILABLE_CHECK_MSG,
      - IS_UNIQUE_VOLUME_CHECK_MSG,

    - enum STORAGE_CHECK_STATUS extends ECStorageProperties
      - IS_UNIQUE_POOL_CHECK_STATUS,
      - IS_POOL_IN_MAINTENANCE_CHECK_STATUS,
      - IS_POOL_AVAILABLE_CHECK_STATUS,
      - IS_UNIQUE_VOLUME_CHECK_STATUS,

  • StoragePoolProperties.java
    - enum POOL_API_REQUEST extends ECStorageProperties
      - ...

    - enum POOL_API_RESPONSE extends ECStorageProperties
      - ...

    - enum POOL_MQ_REQUEST extends ECStorageProperties
      - ...

    - enum POOL_MQ_RESPONSE extends ECStorageProperties
      - ...

    - enum POOL_PROPERTIES extends ECStorageProperties
      - POOL_ID: 'pool_id',
      - POOL_NAME: 'pool_name',

    - enum POOL_EVENT_PROPERTIES extends ECStorageProperties
      - POOL_ID: 'Pool ID:',

    - enum POOL_MESSAGES extends ECStorageProperties
      - POOL_NAME_ALREADY_USED: 'pool name already used'
      - POOL_NAME_IS_NOT_USED: 'pool name is not used'
      - INVALID_POOL_NAME: 'invalid pool name'
      - POOL_IS_AVAILABLE: 'pool is available'
      - POOL_IS_NOT_AVAILABLE: 'pool is not available'
  • StorageVolumeProperties.java
    - enum VOLUME_API_REQUEST extends ECStorageProperties
      - ...

    - enum VOLUME_API_RESPONSE extends ECStorageProperties
      - ...

    - enum VOLUME_MQ_REQUEST extends ECStorageProperties
      - ...

    - enum VOLUME_MQ_RESPONSE extends ECStorageProperties
      - ...

    - enum VOLUME_PROPERTIES extends ECStorageProperties
      - VOL_ID: 'vol_id',
      - VOL_NAME: 'vol_name',

    - enum VOLUME_EVENT_PROPERTIES extends ECStorageProperties
      - VOL_ID: 'Volume ID:',

    - enum VOLUME_MESSAGES extends ECStorageProperties
      - VOLUME_NAME_ALREADY_USED: 'volume name already used'
      - VOLUME_NAME_IS_NOT_USED: 'volume name is not used'
      - INVALID_POOL_NAME: 'invalid volume name'

Chapter 5

  • Manage checked exceptions
    private static Unsafe getUnsafe()
   {
       try
       {
           Field f = Unsafe.class.getDeclaredField("theUnsafe");
           f.setAccessible(true);
           return (Unsafe) f.get(null);
       }
       catch (Exception e)
       {
           throw new RuntimeException(e);
       }
   }
   private static final Unsafe unsafe = getUnsafe();
  • Higher Order Functions
  function isPrime(num) {
    return num > 2 &&
      !Immutable.range(2, num)
         .some(function(){
            return num % n === 0;
         })
  }

  Range(2, 50).filter(function(n){
    return isPrime(n);
  }).toList();

  - without higher order

  ArrayList results = new ArrayList();
  for (int i = 1; i < 200; i++) { //stateful variables
    boolean isPrimeNumber = true; //more stateful variables
    for (int j = 2; j < i; j++) { //even more...
      if (i % j == 0) {
        isPrimeNumber = false;
        break;
      }
    } 

   if (isPrimeNumber) {
     results.add(i); //what if this was parallel?
   }
  }

  - solving the bigger problems
  - old way
  var primes = [];
  var i = 0;
  while(primes.length < 10000) {
    if(isPrime(i)) {
      primes.push(i);
    }
    i++;
  }

  - new way
  var primes = Range(1, Number.MAX_VALUE).filter(function(n){
    return isPrime(n);
  }).take(10000);

  • Chapter 6
  - rule based programming
  - alternatively known as condition, action pair programming

  - Rules
    - Rule      Condition       Action
    - R1         C1                 A1

  - similar to events based programming
  - rule based is 2 step process
  - Events
    - Event    What Happened       Handler
    - E1         xyz                           do this

  - Implementation
  - Tasks
    - contain module state
    - a set of rules
    - a goal
    - applyRules()
  - Module
    - contain one or more tasks
    - operates by repeatedly calling applyRules() method
    - events may cause a task to fall out of its goal state

  while (! goalSatisfied()) {
      for (rule : rules) {
          if (preconditionSatisfied(rule)) {
             execute(rule.action);
          }
      }
  }
  - ref - http://blog.acolyer.org/2016/01/19/dcft/

  • Chapter 7
ref  - https://github.com/npryce/make-it-easy
@AmitKumarDas AmitKumarDas self-assigned this Dec 23, 2015
@AmitKumarDas AmitKumarDas changed the title An attempt towards Non-Procedural coding An attempt towards non-procedural programming Dec 24, 2015
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant