question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

RFC: Consistent API

See original GitHub issue

Okay, so my thoughts came together this morning 😃

I want to change the API surface of Cerebral to:

import { Controller, Module, Provider, Compute } from 'cerebral'

These are the constructs that Cerebral consists of and you use them like this:

Controller

The controller takes a module and options.

const controller =Controller(rootModule, {
  devtools: null
})

Module

The module is how you structure your application.

const app =Module({
  state: {},
  signals: {},
  providers: {},
  modules: {},
  catch: null
})
  1. Providers are now an object instead of an array. This makes a more sense as providers needs a name and we do not need this provide factory:
const app =Module({
  state: {},
  providers: {
    http:HttpProvider({})
  }
})
  1. The only way to catch an error now is at the module level. Errors propagate up to parent modules if not caught. Meaning there is no signal specific error catching or “global”. “Global” would be your root level module.

You still have a callback version

const app =Module(({ name, path, controller ) => ({
  state: {}
}))

Provider

Providers will now have a stronger concept. The concept is being the API between your application and your tools of choice. It can only be defined in one way, an object with methods. This makes things consistent and also enforces the idea that you think of a provider as a “bridge” between your app and the tools your are using.

const myProvider = Provider({
  foo() {}
})

With existing context:

const myProvider = Provider(({ http }) => ({
  foo() {
    return http.get()
  }
}))

All providers defined this way is automatically cached and wrapped for debugger purposes. You can still just add a tool if you want to:

Module({
  providers: { uuid }
})

But these are not wrapped.

Compute

This is just a change to be consistent with the other APIs:

const myComputed =Compute(state`foo`, (foo) => ())

Catch

There is no need to use Map for catching errors. Also catching is now moved to one spot… the module.

Module({
  signals: {},
  catch: [
    [Error, sequences.catchError]
  ]
})

Allrighty… please comment and I will get to work on this as soon as we agree. It is of course a breaking change, but it is small. This is what needs to be changed in the apps:

  1. Change controller configuration to take in a top level module
  2. Wrap all modules in Module constructor
  3. Change configuration of providers to use object

Here is a video as well: https://drive.google.com/open?id=0B1pYKovu9UpyT1NTWVlHN0c2ZTA

Issue Analytics

  • State:closed
  • Created 6 years ago
  • Reactions:1
  • Comments:6 (4 by maintainers)

github_iconTop GitHub Comments

3reactions
christianalfonicommented, Dec 4, 2017

@nickbreaton Hehe, thanks for your input 😃 This is certainly interesting. It does make sense to make computed part of the module, allowing for the module tag to be used across action and connect usage. I will have to do a little bit of research here in case there is something I am missing, but it makes total sense. Thankful for fresh eyes here! 👍 😃

2reactions
nickbreatoncommented, Nov 21, 2017

I’m fairly new to Cerebral, and I have yet to built anything real with it, but I have built some things with Redux, MobX, and mobx-state-tree, so I feel like I can still understand some of the problems in this space.

The new module tag is awesome! I feel like it’s super important to be able to move modules are our applications, but not have to refactor any internal module code. The module tag us pretty close, but there is still one piece that I feel is pretty important. Computed properties.

As I was reading over this issue and related PR, something came to mind.

Like I said, I’m fairly new, but if this would be possible, I think it would be awesome. What if we could use compute at the module level:

/*
  Define our compute, but be able to use the module tag.
*/
const getFullName = Compute(module`firstName`, module`lastName`, (firstName, lastName) => {
  return `${firstName} ${lastName}`
})

/*
  Attach our compute to our module, by having a "computed" 
  key available to us. 
*/
const user = Module({
  state: {
    firstName: 'Joe',
    lastName: 'Smith'
  },
  computed: {
    fullName: getFullName
  }
})

/*
  We could then also have a "computed" tag.
  An example of using the "computed" tag in @cerebral/react:
*/
connect({
  firstName: state`user.firstName`,
  fullName: computed`user.fullName`
}, ({ firstName, fullName }) => (
  <div>
    <p>{firstName}'s full name is {fullName}</p>
  </div>
))

I think this would dramatically increase portability of compute, which for me personally, is a huge problem when using Redux selectors, and seems just about the same level of mess in Cerebral currently.

This is somewhat inspired by mobx-state-tree’s views layer.

If I’m completely off my rocker, please shoot me down. If this is something worth considering, I would gladly make a new issue for it. I would be willing to help with implementation as well, but it may take me some time to get up to speed.

Cerebral seems like an awesome project! Thanks for taking the time to read this.

Read more comments on GitHub >

github_iconTop Results From Across the Web

RFC 2614 - An API for Service Location - IETF Datatracker
RFC 2614 Service Location API June 1999 1. Introduction The Service Location API is designed for standardized access to the Service Location Protocol...
Read more >
RFC: Restful Secondary Key API - Just a Theory
I've been working on a simple CRUD API at work, with an eye to make a nicely-designed REST interface for managing a single...
Read more >
RFC 9205: Building Protocols with HTTP
Applications often use HTTP as a substrate to create HTTP-based APIs. This document specifies best practices for writing specifications that use HTTP to ......
Read more >
Mini RFC - Consistent API for data loaders #5263 - GitHub
Background deck.gl core includes two loaders: json and image There are 4 official layers that currently require specialized loaders: layer ...
Read more >
T51219 Gawain API general consistency RFC
Currently the API doesn't seem very consistent. No prefix identifier for headers, constants, structs and functions (this is something many C API's do...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found