Gothic
The successor to Ghost and Lapiz.
Gothic runs in Go on a dedicated server. It is not meant to run behind Apache or share the machine with other services. But it can make efficient use of very small machines and scale out to utilize additional nodes efficiently.
Look into dynamic linking for this.
Before I get carried away (and I have a LOT to do with compiler-compilers) lets try a Gothic Alpha
Parser Generator
This ends up being the core. So much of what I want to do involves moving descriptions between environments.
Go Yacc
https://golang.org/src/cmd/yacc/yacc.go
It's written as a tool. I could pull the guts out into a package. This could also be submitted back to the go community.
PEG
https://github.com/pointlander/peg
Components
- Blueprints: schemas, data designs
- Mason: server level compiler
- Carpenters: UI (JS,CSS,HTML) compiler
- Arch: UI runtime
- Vault: Persistance
- Portal: API/transport
- Spire: UI
- Lancet: Core(server) framework
Blueprints
Gothic is built around blueprints. A blueprint is like a model or schema. It defines a set of data and it's relationships.
Blueprints also define special modifies for:
- UI
- Storage
- non-persistant fields
- manually defined indexes
- auto-indexing
- API
- Validation
All instances are entities. They have an id field, a guid.
Arch
This is the hard bit. How to take the blueprints and translate them to something powerful, mostly automated, but still flexible.
I think it will use 2 Web Workers + the main window by default. One worker will handle any processing, the other will handle networking. If the models are all encoded as ArrayBuffers, they can be passed around easily. I can also translate their code to Asm.js. But this means they cannot interact in Asm.js.
Unlike Lapiz, I will not do strict privacy, instead relying on the compiler to enforce this.
Just figured out function tables in Asm.Js, that puts a lot back on the table.
Vault
Vault is the persistence layer, an object store and caching mechanism.
Store
- obj.EntityId() []byte
- obj.Serialize() string
- gothic.NewContainer(zero Obj, directory) Container
Serializing is a bit tricky. Can't use Gob because it needs to not follow Entity references, but instead replace them with Entity Ids. Further, I'd like a default serializer to "just work", but I'd also like to allow users to either write their own or have a chance to store hidden state.
Also, it would be best if default serialization happened in such a way that a subset of fields could be loaded without hydrating the whole object.
Be sure (later step) to add a mutex lock to the Entity struct. It's mostly not necessary, but during serialization, another process could access and modify the object.
My first approach was to build a tree of the reflect values. This allows me to parse through it once to get the size, then again to encode. But I'm doing all that to avoid resizing and copying the byte buffer. That's dumb though, I'll end up doing far more work and allocating far more space managing the tree. Better to just resize the array as I go. Also, I may be able to add some hinting or heuristics later that will help allocate the correct size slice.
Cache
- WeakRef map
- Finalize
- PostGC
The WeakRef map tracks active Entities so that we don't have multiple clones instantiated. I can also do a mutex lock here so that two routines don't hydrate at the same time, but the lock should only be on hydration, not on request. I could even add an arbitrary number of locks and use part of the ID. Finalize will transfer an object from Active to Cached. PostGC we will check memory usage and if it's too high, we'll (proportionally) drop the oldest part of the cache.
Index
- map[string]LessThan(obj, val) bool
This allows us to do comparisons. To compare two objects, we extract the field from one and pass it in as a value. I could break a struct up into indexed and non-indexed fields. The main struct would be the non-indexed fields with the indexed fields embedded. This allows me to hold a reference to the indexed fields, but write the object to disk.
Query
- Filter(obj) bool
Not much explanation needed. However, with this setup, devs need to be aware of their indexes and first filter using indexes then filter using explicit filters. I need to find a way to make this easier. The best bet would be a standard Filter interface that can be reduced to less-than operations.
Crazy Idea
Go has function pointers and unsafe. It may be possible to generate Go code, spin it up in separate process, pass a pointer through a pipe, and copy the function.
Spire
This manages CSS and HTML templates. I want something very much in line with LapizUI. We have Templates and Meta-Templates. They are logic free and instead expose hooks that need to be handled in application logic. When an entity is merged with a template it can be rendered to a target. A Meta-Template can be merged with a blueprint to produce a template.
Themeing is broken up a bit more here than in most frameworks. One portion of themeing handles page blocks.
Templates and Meta-templates have types (edit, create, full, short, list) and are arranged in packages (though a single template can be a package). It will be possible to request that a specific template or meta-template be used in some instance, but the more common procedure will be to choose the type and have the theme engine choose the best fit. This will be done with a precedent order. So a theme will ship with some default meta-templates. Modules can define their own templates (for their types).
Panels
From Panel Painting
Css is great for styles but pretty terrible at layout. I'd like to add a container tool that manages page layout. Containers, under the hood, are a collection of CSS, HTML and JavaScript.
So a Page is a top level panel. A panel has some number of slots, which may be fixed or variable. Each slot can hold another panel or a view.
Some panels are simple, just a div. Some can be moderately complex like column layouts, sticky-footers, fixed-expanding-headers. And we can build highly complex containers like Tetris-Panels (Pintrist), tabbed panel, infiniscroll. Panels will be distributed as modules.
Look at Pattern Lab
Widgets and Views
A widget refers to the combination of a view and the view-logic that supports it. A view contains no logic, only logic hooks.
When generating a view, it can be done explicitly with a template and a context, but it can also be done with a template-class. A template-class will match or generate the correct template. This allows meta-templates to be used. So asking for "Edit" may fall back to "Upsert" or to an "Edit"-meta-template that will be used to generate an "Edit" template for the context class.
Illuminate
This will manage the "look and feel" of the site. The goal is to hold aesthetic decisions, and work with Panels to layout the site.
The core features will be hold color palettes, fonts (family, kerning) and so forth.
Credential Model
There are two types of credentials. One is token access. This is where a user or process gains access by having access to a token object. The other is secret knowledge. This is like a password.
Using a CMS as an example; a user could sign in with a username and password. Now they have this credential object to access and edit content. But rather than giving each user access to individual objects, we create roles, which are access tokens and user object is only used to retrieve a role token.
Portal
This is the API layer. It primarily works over websockets. A user or process provides a request. The system uses their credentials to see if they have access to the results of the request. The objects that match, that the requester can access, are returned.
Though Experiments
- Basic relay chat server
- Wiki
- Work logs
- My To-do, that has never actually been completed
Terms and Ideas
- Module: A unit of code that adds functionality to a project
- Package: A collection of modules and packages
- Handler: A unique event handler. Modules and packages may require handlers to be enabled.
I'd like to build in a good set of testing tools. Go already has unit testing, but I'll want to be able to run that as JS too. I'd like comprehensive integration testing. A dev/qa can pull up a page in a browser and hit "go" and it will run through all the defined tests and save the results including browser information.
I want a full dev stack - git, bug tracking, features. Dev's won't need an ide or even an editor, everything can be done through a thin-client.