File System Recipes Specification

Specification Version 0.0.1 - Draft For Team Feedback

Published June 25, 2021

Taylor Brockman taylor.brockman@brainpowersoftware.com

This document is semantically versioned https://semver.org/

Executive Summary

File system recipes (fsr) are a method of describing your software application’s functionality using convential paths and filenames within a computer file system.

File system recipes (fsr) are inspired by the ‘convention over configuration’ software design pattern, which begin to gain popularity with software development teams in 2006.

This document specifies the requirements for how files and paths must be named within file systems to ensure they are file system recipe compliant.

This document is written at a time we are expanding the definition of recipes, so that every new service interprets the file and path naming conventions in a consistent way, regardless of the technology stack.

Benefits of file system recipes (fsr) include:

  1. Fsr applications behave as expected when files and paths are named in a certain way.

  2. Fsr applications can be implemented using a minimum number of files and paths.

  3. Fsr applications can be implemented with a minimum of repetition and boilerplate code.

  4. Users can easily and arbitrarily extend functionality of a service to meet their needs.

  5. Developers can define new services and distribute them to users in a consistent, easy to understand way.

File system recipes should:

File system recipes are supported by all current Brain Power Software services including Flatmap, Visual Delivery, Information Kitchen, PDF Transformer, and Receipt Delivery.

Fsr will be the single form of application and automation definition for all new services developed and projects implemented in the future.

Fsr are typically hosted in version-controlled in git repositories following best practices of branching and organization.

Fsr make it easy for technical and non-technical users to collaborate.

Fsr make it easy for technical users to extend a service’s capabilities and customize it’s behavior in any way necessary to meet your application’s use cases.

File System Recipe Specification ( file-system-recipe fsr )

+R> Fsr is an abbreviation this is both singular and plural. It means ‘File system recipe’ singular and ‘File system recipes’ plural; you don’t need to write fsrs to mean more than one file system recipes. You should still use the apostrophe s for possessive: “The fsr’s creation date”, but this can often be dropped: “The fsr creation date”.

File system recipes contain files:

  1. Fsr application logic is defined in ‘Instruction’ files, each instruction type is defiend by the recipe in which it lives. Many of the popular instruction files types are: TypeScript, Scala, JavaScript, Css, Json Configuration, Text Values, and Handlebars Html Templates.

  2. Fsr application data is defined in ‘Ingredient’ files, each ingredient type is defined by a common ingredient reader (Csv, Excel, Json Data, Xml, Text Data, Markdown), but recipes may extend their known ingredient types (Example: Fixed-width Data Files, SqlLite Databases)

  3. Fsr may also contain other files that are neither ‘Instruction’ or ‘Ingredient’ files, these are called ‘Unrecognized’ files, and are typically configuration files or working files for use in other applications like .gitignore or editor swap files.

Recipe Rules for Filesystems in General (Filenames + Pathnames)

+R> ‘Path’ is the name of a filesystem container where you can find files and other paths. Sometimes people refer to these as ‘Directories’ or ‘Folders’. We are standardizing on ‘Path’.

+R> Filenames and Pathnames are strings that must be Unix Filesystem compliant and Windows Filesystem compliant and not contain any of the reserved chatacters: < > : “ / \ ? * &.

Filesystem specs:

  • Unix: https://www.cyberciti.biz/faq/linuxunix-rules-for-naming-file-and-directory-names/
  • Windows: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file

+R> It’s recommended to only use Alpha Numeric characters in filenames, including: a-z A-Z 0-9 - _ .

+R> It’s discouraged to use special characters like % ^ $ [ ] , in filenames.

+R> Separator (sep) symbols include: ‘-‘ (Dash), ‘ ‘ (Space)

+R> Filenames and Pathnames are split by the (sep) chatacter into a sequence of Words.

+R> Some words are ‘keywords’, meaning they’re used to find entries in known software lookup routines. For example, the recipe types are keywords, and each recipe can define it’s own instruction keywords.

+R> Some words are not keywords and will pass-thru to your application in exactly the format and uppercase/lowercase in which they are found in the filenames and pathnames.

+R> The order of the words in filenames and pathnames has significance.

Sample: ‘data-rewards’ is two words: [ ‘data’, ‘rewards’ ]

+R> If multiple separators exist in sequence in the Filename or Pathname, they will be combined into a single separator.

+R> If separators exist at the front or end of the Filename or Pathname, they will be removed.

Sample: ‘View Rewards ‘ is two words: [ ‘View’, ‘Rewards’ ]

+R> File names and path names are case sensitive. Uppercase + lowercase filename characters matter in many cases, such as ‘feature name’.

Debate this: The exception to case sensitivity is when keywords are looked up from filenames, (for example, an instruction functionName), the lookup to the known lookup tables is case insensitive.

Recipe Paths follow this pattern:

(order?)(sep?)recipeType(sep?)(recipePurpose?)((sep?)(recipeParameters?))*/

+R> A ‘Receipe Path’ is any path that matches a recipe keyword in your reactor’s registry. Recipe paths typically live at the top-level path of your project.

English Recipe Diction

“Recipe Registry” - The set of known recipes that the available services can interpret at the time your applciation starts. The base registry set includes recipe types: ‘data’, ‘attach’, ‘info’, ‘view’, ‘receipt’, ‘macro’, but new service types may be defined in the future.

“Recipe Type” - A type of recipe available in the Recipe Registry, this is typically a lower-case short string, but because this is a keyword lookup, It can be upper-case or lower-case, Example: ‘Data’ == ‘data’.

“Recipe Purpose” - An additional word in the recipe path that can help differentiate multiple recipes of the same type. Sample: view-rewards, view-notification

“Recipe properties” - Any additional words beyond the recipe purpose that can defined arbitrary properies. (Future placeholder reservation)

Receipe Path Samples

  • data/ => { recipeType: data }
  • data-rewards/ => { recipeType: data, purpose: rewards }
  • data-aca-review/ => { recipeType: data, purpose: aca, properties: [ review ] }
  • Receipt/ => { recipeType: receipt }

Recipe Instruction Filenames follow this pattern:

(order?)(sep?)functionName(sep)featureName((sep?)(factors?))*.extension

+R> An ‘Instruction’ is any filename or path that matches a function known by a recipe in your reactor’s registry and located within that recipe’s path.

+R> Function Names must be javascript/typescript compliant symbols, plus filesystem compatible.

+R> Feature Names cannot contain the separator: [- ], recommend camelCase or _ in feature names

Recipe Instruction Filename Samples

  • add-display.ts => { functionName: add, featureName: display, extension: ts }
  • AddString Display.scala => { functionName: AddString, featureName: Display, extension: scala }
  • email-success.json => { functionName: email, featureName: success, extension: json }
  • 01-email-blocker.json { order: 01, functionName: email, featureName: blocker, extension: scala }

Recipe Instruction Paths follow this pattern:

(order?)(sep?)functionName(sep)featureName((sep?)(factors?))*/

Recipe Instruction Path Samples:

  • 01 Receipt/ => { order: 01, functionName: Receipt }
  • 01 Receipt Markdown/ => { order: 01, functionName: Receipt, featureName: Markdown }
  • Pattern01 HeroImage/ => { order: Pattern01, functionName: HeroImage }
  • Pattern01 HeroImage PeoplePhotos/ => { order: Pattern01, functionName: HeroImage, featureName: PeoplePhotos }
  • Pattern01 HeroImage PeoplePhotos If ShowPeople/ => { order: Pattern01, functionName: HeroImage, featureName: PeoplePhotos, factors: [ If, ShowPeople ] }
  • Identity Census EE_ID => { functionName: Identity, featureName: Census, factors: [ EE_ID ] }
  • Join Benefits EE_ID to Census EE_ID => { functionName: Join, featureName: Benefits, factors: [ EE_ID, to, Census, EE_ID ]}

English Instruction Dictation

“Instruction Order” - The lexigraphical order of when this instruction is performed within the sequence of all instructions in this path.

“Instruction Function” - The name of the Recipe API function that the reactor calls when it is time to perform this instruction.

“Instruction Feature” - A distinctive name to differentiate this instruction from the other instructions in the path. Features may be arbitrary: they can pass thru the recipe (in the case of adding a feature in a data recipe) or may mean something specific to the recipe (in the case of setting who should be emailed success receipts).

“Instruction Factors” - An expression of extra conditions or instruction specificity available to this instruction.

Definitions: “perform” - carry out, accomplish, or fulfill (an action, task, or function),

Definitions: “present” - (a form of entertainment) to an audience.

Definition: “feature” - a distinctive attribute or aspect of something.

Definitions: “factor” - a circumstance, fact, or influence that contributes to a result or outcome.

Recipe API Class Design

class Recipe { 
    constructor(public path: string,
                public recipePath: RecipePath ) {
}


class RecipePath {
    constructor( public path: string,
                 public recipeRegistry: RecipeRegistryEntry,
                 public purpose?: string,
                 public parameters?: string[],
                 public order?: string ) {
        //
    }
}



export class RecipeInstructionFilePath {
    constructor( public path: string,
                 public functionEntry: RecipeFunctionEntry,
                 public featureName?: string,
                 public factors?: string[],
                 public extension?: string,
                 public order? : string ) {
        //
    }
}


class RecipeRegistryEntry {
    constructor( public recipeType: string,
                 public functionNames: string[] ) {

    }
}