diff --git a/content/enterprise/prototype/index.md b/content/enterprise/prototype/index.md index 982fe38..b4011cc 100644 --- a/content/enterprise/prototype/index.md +++ b/content/enterprise/prototype/index.md @@ -8,13 +8,14 @@ template = "post.html" tags = [] +++ +NB: It's been a while since I wrote a post here. Since I began working at Epic, I've found it hard to motivate myself to even work on projects, let alone writing, after work hours. Hopefully I can pick it back up. + This past weekend, while on my trip to Minneapolis, I completed a very early prototype of "enterprise", a new UI framework I've been kind of envisioning over the past couple of weeks. While the UI framework is mainly targeted at web apps, the hope is that with a bit more effort, native UIs can be produced with almost no changes to existing applications. Before I begin to describe how it works, I'd like to acknowledge [Nathan Ringo][1] for his massively helpful feedback in both the ideation and the implementation process. ## Goals of the project -* **Complete separation of business logic from UI.** Theoretically, one could completely retarget the application to a completely different platform (mobile, web, native, something new that will pop up in 5 years), without changing any of the core logic. It does this by introducing [DSL][2]s that are completely architecture-independent. +* **Complete separation of business logic from UI.** Theoretically, one could completely retarget the application to a completely different platform (mobile, web, native, something new that will pop up in 5 years), without changing any of the core logic. It does this by introducing [declarative][4]-style [DSL][2]s that are completely architecture-independent. * **Maximally static component relationships.** Like [Svelte][3], I'm aiming to resolve as many relationships between elements as possible during compile-time, to avoid having to maintain a full virtual DOM at runtime. -* ## Prototype @@ -44,8 +45,54 @@ view { } ``` +This looks a lot closer to {React, Vue, Svelte, component structure}-ish code. The idea now is that the "compiler", as I've come to call it, reads the entire specification of the code and creates a sort of dependency graph of actions. For clarity, let's assign some IDs first: +* Let the `TextBox`'s value attribute be `view_value`. +* Let the `{name}` code segment in "Hello, name" be `view_name`. +* Let the model's name field be `model_name`. + +Now we can model this as: + +```dot +digraph "dependency graph" { + graph[bgcolor="transparent", class="default-coloring"]; + rankdir="LR"; + + "view_value" -> "model_name" + "model_name" -> "view_name" +} +``` + +The arrows in this graph indicate a dependency where changes to `view_value` propagates down the graph until everything else is changed. For the initial prototype, the data structure passed through this graph is simply a string, but with encoding magic and additional specifications, we can add rich text later. What this means the compiler then generates code that looks something like (but not exactly): + +```rs +fn create_view_value(model: &mut Model) -> INode { + let el = (...); + el.add_event_listener(|evt: InputListener| { + let new_value = el.get_attribute("value"); + model.name = new_value; + view_name.set_text(new_value); + }); + el +} +``` + +There's some complications involving the exact model representation in memory as well as how web attributes are accessed that makes the real code a bit different, but from this example you should be able to see that our "compiler" generated real code that matches our specification above. + +The full code for this can be found [here][5]. + +## Future + +Obviously not everyone's application is as simple as a linear dependency graph of simple string values. In fact, I even cheated a bit to get this prototype to function; here's some of the shortcuts I took: + +* I mostly hardcoded web elements in instead of making platform-independent abstractions. +* I hardcoded the actual specification for the app myself since the DSL doesn't have a real syntax yet. +* All data are string types. + +I'll be working on this some more in the coming weeks, so I'll try to keep updates posted here a bit more frequently. Until then, thanks for reading! [1]: https://remexre.xyz [2]: https://en.wikipedia.org/wiki/Domain-specific_language [3]: https://svelte.dev +[4]: https://en.wikipedia.org/wiki/Declarative_programming +[5]: https://git.iptq.io/michael/enterprise diff --git a/sass/_graph.scss b/sass/_graph.scss new file mode 100644 index 0000000..b088d52 --- /dev/null +++ b/sass/_graph.scss @@ -0,0 +1,15 @@ +.graphviz { + .graph.default-coloring { + ellipse, path, polygon { + stroke: $text-color; + } + + text { + fill: $text-color; + } + + * { + font-family: $sansfont; + } + } +} diff --git a/sass/main.scss b/sass/main.scss index e7aa9aa..fc342c9 100644 --- a/sass/main.scss +++ b/sass/main.scss @@ -11,6 +11,7 @@ $monofont: "Roboto Mono", "Roboto Mono for Powerline", "Inconsolata", "Consolas" $small-text-color: lighten($text-color, 10%); $link-color: royalblue; @import "content"; + @import "graph"; } @media (prefers-color-scheme: dark) { @@ -19,4 +20,5 @@ $monofont: "Roboto Mono", "Roboto Mono for Powerline", "Inconsolata", "Consolas" $small-text-color: darken($text-color, 10%); $link-color: lightskyblue; @import "content"; + @import "graph"; }