Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Playful Features ... Feature Based Development that "Plugs and Plays"

Playful Features ... Feature Based Development that "Plugs and Plays"

Feature-Driven Development (FDD) has become more prevalent in today's landscape, and for good reason! FDD is a lightweight Agile technique, manifest in a project structure where your code is organized by what it accomplishes (i.e. features), rather than lumping all modules of like types into separate blobs of components, routes, logic, actions, etc. This technique greatly improves your code comprehension because there is a direct correlation between the problem space (the requirements) and the implementation (the code)!

However, FDD involves more than just organizing your project's directory structure into features. You want to encapsulate your features into isolated and self-sufficient modules, and yet they must also be able to collaborate with other features.

Truly isolated FDD is something that is incredibly powerful! You can improve the modularity of your system by loosely coupling your features, making your app easier to understand, develop, test, and refactor. If done right, your features actually become "miniature applications" that simply plug-and-play (where the mere existence of a feature dynamically exudes the characteristics it implements)!

As it turns out there are a number of hurdles to overcome in order to accomplish this. Rather than being left to fend for yourself, a new utility called feature-u (https://feature-u.js.org/) has already tackled these hurdles (check out this teaser - http://bit.ly/feature-u-teaser).

feature-u promotes a new and unique approach to code organization and app orchestration.

With feature-u ...

- your features can be encapsulated and isolated
- they can collaborate with other features in an extendable way
- your components can employ cross-feature composition (even injecting their content autonomously)
- your features can initialize themselves
- they can be activated or deactivated at run-time
- and as a bonus, your frameworks will even auto-configure with only the active features (via a plugin architecture)

In short, your features can become more playful ... they can plug-and-play!

feature-u opens new doors into the exciting world of FDD. It frees you up to focus your attention on the "business end" of your features!

Kevin Bridges

August 23, 2019
Tweet

More Decks by Kevin Bridges

Other Decks in Programming

Transcript

  1. Playful Features
    Kevin Bridges
    Applied Software Technologies
    [email protected]
    @kevinast
    https://bit.ly/feature-u-pres
    slides, syllabus, articles, docs, and repo!

    View Slide

  2. • Married, Father, Grandfather
    • 40 yrs in software (20 yrs consulting)
    • Retired
    • Be nice to the old guy :-)
    Kevin Bridges
    Applied Software Technologies
    [email protected]
    @kevinast
    https://bit.ly/feature-u-pres
    slides, syllabus, articles, docs, and repo!

    View Slide

  3. Playful Features
    https://bit.ly/feature-u-pres
    slides, syllabus, articles, docs, and repo!
    Feature-Based Development
    that
    "Plugs and Plays"

    View Slide

  4. SideBar:
    feature-u
    docs
    https://feature-u.js.org/

    View Slide

  5. View Slide

  6. Goals
    • Requirements based
    • Encapsulation
    • Self Sufficient
    • Plug-and-Play
    Hurdles
    • Isolation vs. Collaboration
    • Start-Up Initialization
    • Framework Configuration
    • UI Composition
    • Feature Enablement
    In short, how do we achieve a running
    application from these isolated features?

    View Slide

  7. Two Primary
    Tenets
    needed to
    Achieve
    our
    Goals
    1. Feature Runtime Consolidation
    2. Feature Collaboration

    View Slide

  8. 1.

    View Slide

  9. 2.

    View Slide

  10. View Slide

  11. How is Cross Feature Communication achieved
    in a way that doesn't break encapsulation?
    2.

    View Slide

  12. The feature-u Solution

    View Slide

  13. Authorization
    Base UI
    Eateries
    View
    Discovery
    View
    GPS
    Location
    PWA
    Dev
    Sandbox
    Ultimate Goal
    2. Startup Initialization
    Encapsulation
    1. Requirement Based
    Features
    4. Feature Collaboration
    ==
    Mini Apps
    3. Feature Enablement

    View Slide

  14. Covered in this Session:
    1. Simplified App Startup
    a. App-Specific Initialization in Features
    b. Auto-Configuration of Frameworks
    2. Feature Enablement
    3. Cross-Feature Collaboration
    a. Cross-Feature Sharing
    b. Cross-Feature UI Composition
    4. A/B Feature Swap
    5. Plug-and-Play

    View Slide

  15. eatery-nod-w
    https://github.com/KevinAst/eatery-nod-w

    View Slide

  16. 1. Simplified App Startup
    I can start your app in 1,577 lines of code!
    1

    View Slide

  17. 2. Plug-and-Play
    Feature Enablement

    View Slide

  18. 3. A/B Swap
    Mock Services

    View Slide

  19. View Slide

  20. View Slide

  21. View Slide

  22. View Slide

  23. How does
    feature-u
    accommodate:
    1. Feature
    Runtime
    Consolidation
    APP INITIALIZATION FRAMEWORK
    CONFIGURATION

    View Slide

  24. appWillStart({fassets, curRootAppElm}): rootAppElm|void
    invoked early in the app startup process
    … supports accumulative static root DOM injection
    appDidStart({fassets, [appState, dispatch]}): void
    invoked immediately after app starts
    … triggers “app is running” processes
    Feature Encapsulation
    of
    App Startup
    appInit({showStatus, fassets, [appState, dispatch]}): promise|void
    invoked later in the app startup process
    … supports blocking async initialization
    1. Feature Runtime Consolidation
    Application
    Life Cycle
    Hooks

    View Slide

  25. 1. Feature Runtime Consolidation
    Extendable
    Aspect
    Plugins
    feature-u is extendable!
    Framework Configuration
    Goal

    View Slide

  26. 1. Feature Runtime Consolidation
    Extendable
    Aspect
    Plugins

    View Slide

  27. 1. Feature
    Runtime
    Consolidation
    eatery-nod-w
    https://github.com/KevinAst/eatery-nod-w

    View Slide

  28. 1. Feature
    Runtime
    Consolidation
    import React from 'react';
    import Expo from 'expo';
    import {LayoutAnimation} from 'react-native';
    import {launchApp} from 'feature-u';
    import {createReducerAspect} from 'feature-redux';
    import {createLogicAspect} from 'feature-redux-logic';
    import {createRouteAspect} from 'feature-router';
    import features from './feature';
    import SplashScreen from './util/comp/SplashScreen';
    // launch our application, exposing the feature-u Fassets object
    // ... facilitating cross-feature-communication!
    export default launchApp({
    aspects: appAspects(),
    features,
    registerRootAppElm(rootAppElm) {
    Expo.registerRootComponent(()=>rootAppElm); // convert rootAppElm to a React Component
    }
    });
    // accumulate/configure the Aspect plugins matching our app's run-time stack
    function appAspects() {
    // define our framework run-time stack
    const reducerAspect = createReducerAspect();
    const logicAspect = createLogicAspect();
    const routeAspect = createRouteAspect();
    const aspects = [
    reducerAspect, // redux ... extending: Feature.reducer
    logicAspect, // redux-logic ... extending: Feature.logic
    routeAspect, // Feature Routes ... extending: Feature.route
    ];
    // configure Aspects (as needed)
    // ... StateRouter fallback screen (when no routes are in effect)
    routeAspect.config.fallbackElm$ = ;
    // beam me up Scotty :-)
    return aspects;
    }
    src/app.js
    src/
    │ app.js ... our mainline - launches app via launchApp()

    ├──feature/
    │ │ index.js ... accumulate/promote all app Feature objects
    │ │
    │ ├──auth/ ... the app's authorization feature
    │ │ │ actions.js
    │ │ │ fassets.js
    │ │ │ feature.js ... expose aspects of interest to feature-u
    │ │ │ featureName.js
    │ │ │ index.js
    │ │ │ logic.js
    │ │ │ route.js
    │ │ │ signInFormMeta.js
    │ │ │ state.js
    │ │ └──comp/
    │ │ SignInScreen.js
    │ │ SignInVerifyScreen.js
    │ │
    │ ├──currentView/ ... more features
    │ │
    │ ├──device/ ... feature to initialize the device
    │ │ │ actions.js
    │ │ │ api.js
    │ │ │ appDidStart.js
    │ │ │ appWillStart.js
    │ │ │ fassets.js
    │ │ │ feature.js ... expose aspects of interest to feature-u
    │ │ │ featureName.js
    │ │ │ index.js
    │ │ │ logic.js
    │ │ │ route.js
    │ │ │ state.js
    │ │ └──init/
    │ │ platformSetup.android.js
    │ │ platformSetup.ios.js
    │ │
    │ ├──discovery/ ... more features
    │ ├──eateries/
    │ ├──firebase/
    │ ├──leftNav/
    │ ├──logActions/
    │ └──sandbox/

    └──util/ ... common utilities used across all features
    directory structure
    import React from 'react';
    import platformSetup from './init/platformSetup';
    import Notify from '../../util/notify';
    /**
    * An app-level life-cycle hook, initializing our feature by:
    * - performing platform-specific setup (iOS/Android)
    * - inject our notify utility in the root DOM
    */
    export default function appWillStart({fassets, curRootAppElm}) {
    // platform-specific setup (iOS/Android)
    platformSetup();
    // initialize notify utility, by injecting it in our App root
    return [React.Children.toArray(curRootAppElm), ];
    }
    src/feature/device/appWillStart.js
    import {createFeature} from 'feature-u';
    import initFireBase from './init/initFireBase';
    /**
    * The **'firebase'** feature initializes the google firebase service,
    * and provides a placeholder for future API abstractions.
    */
    export default createFeature({
    name: 'firebase',
    appWillStart({fassets, curRootAppElm}) {
    initFireBase(); // initialize FireBase
    },
    });
    src/feature/firebase/feature.js
    redux auto configured
    by
    feature-redux Aspect Plugin
    import React from 'react';
    import {Drawer} from 'native-base';
    import SideBar,
    {registerDrawer,
    closeSideBar} from './comp/SideBar';
    /**
    * Inject our Drawer/SideBar component at the root of our app
    */
    export default function appWillStart({fassets, curRootAppElm}) {
    return (
    registerDrawer(ref) }
    content={}
    onClose={closeSideBar}>
    {curRootAppElm}

    );
    }
    src/feature/leftNav/appWillStart.js
    export default launchApp({
    aspects: appAspects(),
    features,
    registerRootAppElm(rootAppElm) {
    Expo.registerRootComponent(()=>rootAppElm);
    }
    });
    src/app.js
    import actions from './actions';
    /**
    * An app-level life-cycle hook that dispatches our bootstrap action
    * that gets the ball rolling!
    */
    export default function appDidStart({fassets, appState, dispatch}) {
    dispatch( actions.bootstrap() );
    }
    src/feature/device/appDidStart.js
    Feature Encapsulation
    of
    App Startup
    • App Initialization (Application Life Cycle Hooks)
    • Framework Configuration (Extendable Aspect Plugins)
    Made possible because feature-u starts the app!

    View Slide

  29. feature-u solution
    Feature
    Enablement

    View Slide

  30. Feature
    Enablement
    export default createFeature({
    name: 'sandbox’,
    enabled: inDevelopmentMode(),
    ... snip snip
    });
    src/feature/sandbox/feature.js
    • by default all Features are active
    • can be disable via enabled Feature directive
    Feature Enablement
    Made possible because feature-u starts the app!

    View Slide

  31. How does
    feature-u
    accommodate:
    2. Feature
    Collaboration
    Cross Feature
    Communication
    Feature Based UI
    Composition

    View Slide

  32. 2. Feature Collaboration
    Cross Feature
    Communication
    fassets
    • fassets facilitate Cross Feature Communication
    • accommodates all Cross Feature Sharing
    • "Public Face" of a feature
    • Open

    • SideBar: fasset (not facet)
    fassets – Feature Assets

    View Slide

  33. 2. Feature Collaboration
    Cross Feature
    Communication
    fassets
    Made possible because feature-u starts the app!

    View Slide

  34. 2. Feature Collaboration
    Cross Feature
    Communication
    fassets
    export default createFeature({
    name: 'featureA',
    fassets: {
    define: {
    'actions.openView': actions.view.open, // openView(viewName): Action
    'sel.currentView': selector.currentView, // currentView(state): viewName
    'sel.isDeviceReady': selector.isDeviceReady, // isDeviceReady(state): boolean
    },
    },
    ...
    });
    defining fassets
    if (fassets.sel.isDeviceReady(appState)) {
    ...
    }
    using fassets
    NOTE: This uses a push philosophy
    code snippet ...

    View Slide

  35. 2. Feature Collaboration
    Feature Based
    UI Composition
    withFassets()
    export default createFeature({
    name: 'common',
    fassets: {
    define: {
    'company.logo': () => , // a react component
    },
    },
    ...
    });
    defining logo
    code snippet ...
    function MyComponent({Logo}) {
    return (



    ... snip snip
    );
    }
    export default withFassets({
    component: MyComponent,
    mapFassetsToProps: {
    Logo: 'company.logo',
    }
    });
    injecting fasset component properties
    HoC
    Higher-order Components

    View Slide

  36. 2. Feature Collaboration
    Feature Based
    UI Composition
    useFassets()
    export default createFeature({
    name: 'common',
    fassets: {
    define: {
    'company.logo': () => , // a react component
    },
    },
    ...
    });
    defining logo
    code snippet ...
    function MyComponent({Logo}) {
    return (



    ... snip snip
    );
    }
    export default withFassets({
    component: MyComponent,
    mapFassetsToProps: {
    Logo: 'company.logo',
    }
    });
    injecting fasset component properties
    export default function MyComponent() {
    const Logo = useFassets('company.logo');
    return (



    ... snip snip
    );
    }
    useFassets()
    feature-u V2
    supports
    React Hooks

    View Slide

  37. • Supported by additional fasset directives
    • fassets.use: specify a series of injection needs
    • fassets.defineUse: supply this content
    • Validation Constraints can be specified
    • insuring everything is wired up correctly
    • Wildcards (*) provide additional dynamics
    • allowing content to be injected autonomously
    UI Composition can be a "contract"
    2. Feature Collaboration
    Feature Based
    UI Composition
    Resource
    Contracts

    View Slide

  38. 2. Feature Collaboration
    Feature Based
    UI Composition
    Resource
    Contracts
    createFeature({
    name: 'main',
    fassets: {
    use: [
    'MainPage.*.link',
    ],
    },
    });
    src/features/main/feature.js
    code snippet ...
    export default function MainPage() {
    const mainLinks = useFassets('MainPage.*.link');
    return (
    {/* links section */}
    {mainLinks.map( (MainLink, indx) => )}

    );
    }
    src/features/main/comp/MainPage.js
    createFeature({
    name: 'cart',
    fassets: {
    defineUse: {
    'MainPage.cart.link': () => Cart,
    },
    },
    });
    src/features/cart/feature.js
    createFeature({
    name: 'search',
    fassets: {
    defineUse: {
    'MainPage.search.link': () => Search,
    },
    },
    });
    src/features/search/feature.js
    We have switched to a pull philosophy
    with autonomous injection!!
    2. Feature Collaboration
    Feature Based
    UI Composition
    Resource
    Contracts

    View Slide

  39. 2. Feature Collaboration
    UI Composition
    Resource
    Contracts
    eatery-nod-w
    https://github.com/KevinAst/eatery-nod-w
    LeftNav menu
    in baseUI feature
    eatery screens
    discovery screens

    View Slide

  40. A/B Swap
    change a feature to a new version
    or swap out to a mock service
    or turn on a new feature in it's entirety

    View Slide

  41. A/B Swap
    Services tailor
    a generalized solution
    into an app-specific domain
    greatly simplifying business logic
    Services
    promoted by features

    View Slide

  42. A/B Swap
    service-based features
    through
    Usage Contracts
    Services are promoted through Usage Contracts
    • authService is a required fasset (use)
    • that conforms to an abstract AuthServiceAPI
    • two implementations are provided (defineUse):
    • Real/Mock
    • both implement AuthServiceAPI
    • enablement is mutually exclusive
    feature-u wires everything together

    View Slide

  43. In
    Summary

    View Slide

  44. A final word
    about
    Feature-Based
    Development
    Features should mirror requirements
    Features are a different abstraction
    • because they contain other programming paradigms
    • features are more about a “logical packaging”
    so they plug-and-play
    What does this mean in terms of feature-u?
    Question: "How does feature-u impact my design constructs?"
    Answer: It doesn't!
    feature-u is NON Intrusive!
    • you employ same constructs and styles
    • you use same frameworks in the same way
    • only diff: your scope is smaller (i.e. a feature)
    feature-u frees you up to focus your attention
    on the "business end" of your features!

    View Slide

  45. View Slide

  46. feature-u
    Benefits

    View Slide

  47. Kevin Bridges
    Applied Software Technologies
    [email protected]
    @kevinast
    https://bit.ly/feature-u-pres
    slides, syllabus, articles, docs, and repo!

    View Slide