keithwhor / nodal

API Services Made Easy With Node.js

Home Page:http://www.nodaljs.com/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

CLI: Sensible Defaults, Error Handling and Delete Macros for Generators

nsipplswezey opened this issue · comments

commented

It's easy, and common when starting, to make mistakes with the CLI generators.

So much else in Nodal is easy, straightforward and delivers far above expectations, that relatively speaking a couple CLI errors and needing to memorize specific syntax of CLI are probably one of the greatest barriers to entry. I think this is a striking complement as well as a great area for low-hanging-fruit productivity improvement in Nodal.

Here are a couple examples from experience introducing friends to Nodal, followed by proposals for defaults, error handling and delete/undo

Not specifying a model for a controller
Example:
nodal g:controller v1 without a --for flag generates an empty controller that implements methods that map directly to request type GET POST PUT DEL, which implement this.render() which returns an undefined response.

Sensible Default:
I think the direct method mapping makes sense.
Replace this.render() with this.respond({ message: METHOD + " to " + ENDPOINT + " handled by " + CONTROLLER })

Forgetting to namespace a controller
Example:
nodal g:controller --for tweet
Will generate a controller outside of the namespaced directory, with an non-namespaced endpoint.
This is irritating and common if it's the first time you've thought about namespacing.

Error Handling:
If a namespaced controller exists, prompt the user with "you already have a namespace v1. Would you like to namespace this controller to v1 as well? y or N"

Undo:
nodal g:undo
Undo's whatever last generator command was run in this session.
So if I run a nodal g:controller --for tweet and I don't name space it, and I test my end point and realize 'shit! I meant to name space that.

I my process is:

$ nodal g:controller --for Tweet
$ nodal g:undo
$ nodal g:controller v1 --for Tweet

Or if I do:

$ nodal g:controller v1
$ nodal g:undo
$ nodal g:controller v1 --for Tweet

Or alternatively delete

Might look something like

$ nodal g:controller v1
$ nodal delete v1
$ nodal g:controller v1 --for Tweet

I think honestly the interface should be either undo or delete; not both.

g:delete target is dissonant to me.

Personally I think the undo metaphor is much better, as it fits within the scope of the g: imperative, and my mental model of how I would like a generator to work.

The domain space of genertor's are focused, and pretain to the specific scope of "solve this problem for me." An undo allows me to say "whoops! My bad! I wen't solve THIS problem."

Additionally, nodal generators are typically sequential.

$ nodal g:model Tweet user_id:int body:string
$ nodal g:controller v1 --for Tweets
$ nodal db:migrate

is the first Nodal CLI pattern that any new user learns. So the undo metaphor makes a lot of sense, because I'm just going on step back in my process. Or two if need be. Or three. And then running each of those steps over again.

One challenge with undo is either: reimplement generators using an abstraction that makes them inherently reversible; perhaps using an interface built over an immutable history data structure that exists in the project.

Or implementing something quicker and simpler, but limiting the scope of undo to say the last 3 generator commands. I don't prefer this solution.

Incomplete generator commands

Example
nodal g:controller v1 --for

Error Handling
Just throws a Cannot read property 'length' of undefined

It could give an error message like Error: No model specified after --for flag. It looks like you wanted to build a controller for a specific model, but didn't specify the model.

Namespacing a controller without specifying a model with the --for flag

nodal g:controller v1 testController

Might be expected to generate a default controller named testController and place the controller in the v1 directory.

Instead it throws a somewhat cryptic error:

return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
                                                  ^

Error: ENOENT: no such file or directory, open './app/controllers/v1_controller.js'

Default Behavior

Just generate a default controller in the name spaced directory.

Messing up my model schema

nodal g:model Tweet userId:int body:string

Oh shit. I meant user_id:int body:string

Instead of going into my migration and changing this directly, I'd like to just do a

nodal g:model Tweet userId:int body:string
nodal g:undo
nodal g:model Tweet user_id:int body:string

Forgetting to migrate after generating a new model

This is a common error if Nodal is the first time you're using the migrations abstraction to progressively manage your models and database layer.

The nodal server will crash every time a new model is generated, because a migration is necessary to make the model work.

I don't mind this for two reasons.
First, the error message highlights how readable Nodal error messages are.
Second, it highlights the specific line of code that links our backing schema and tables to our model instances.
Third, models and migrations are seperate concerns. So lumping model creation and db migration might be one fewer command, but comes at the expense of blurring the separation of concerns, which is more valuable.

commented

An empty nodal command generates a Cannot read property 'split' of undefined.
This could be handled better,