TIBET: The Good Parts™
I want to thank the people I worked with at Electric Communities and State Software who helped me discover that deep down there was goodness in this language, especially Chip Morningstar, Randy Farmer, John La, Mark Miller, Scott Shattuck, and Bill Edney.
-- Douglas Crockford, JavaScript: The Good Parts
With a product as comprehensive as TIBET it can be easy to miss the forest for the trees, to scan for features while missing the big picture.
With that in mind, we present "TIBET: The Good Parts", a nod to the original bible of JavaScript best practices and a glimpse of what we believe truly sets TIBET apart.
From a business perspective TIBET:
- eases hiring via a scalable authoring pyramid for teams,
- reduces coding via markup-first authoring including XML,
- simplifies maintenance by separating application and library concerns,
- speeds development via immersive, immediate development tools,
- is open-source and single-sourced, simplifying support.
From a technical perspective TIBET:
- optimizes data-driven development using a unique multi-frame design,
- maximizes code reuse via inheritance, composition, and reflection,
- minimizes conceptual overhead by focusing on tags and URIs,
- simplifies routing, events, and error handling via responders,
- enhances quality through a powerful interactive test harness.
Business Good Parts
Virtually all frameworks work from a technical perspective but most fail to address the three biggest risks to your project: staffing, stability, and support.
We built TIBET to solve the business problems we've run into during our 20+ years of experience building business web applications. Yes, TIBET has some cool technology, but that technology was created to solve real-world business problems.
The Authoring Pyramid
Staffing is the most challenging problem any application platform must address.
Low-code solutions are a direct response to this reality.
Unfortunately, most low-code solutions attempt to conceal the web to the point that they create functional cul-de-sacs or cliffs where your ability to extend, customize, and control your development are sacrificed.
We took a different approach.
TIBET is designed around a concept we call the "authoring pyramid".
TIBET's design aligns the skill requirements for TIBET projects with the distribution of UI, application, and framework-level skills in the market.
The goal is simple enough…
If there are 100 UI (HTML/CSS) developers for every 20 application-level JavaScript developers for every JavaScript guru then projects should require the same distribution of skills or roughly 80% markup and 20% code.
For the TIBET code you do write, the same general 80/20 rule applies.
Less than 20% of the code you write should require a senior developer, putting your guru needs at no more than 4% (20% of 20% overall).
If you can staff 96% of your team from a pool with market-available markup/CSS/JS skills, not gurus, ninjas, or rockstars you've dramatically reduced the #1 risk to your projects -- the inability to staff them properly.
Markup First
In the last 25 years humanity has collectively authored Billions of pages.
Imagine if, instead of HTML, the web had required JavaScript modules, classes, fat-arrow functions, etc. How many pages would we have then?
Now consider the millions of applications running all over the world.
Front-office and back-office applications written in VB, Delphi, PowerBuilder, C++, C#, Java; each trying to find its way onto the web.
Is it scalable to plan that work with a code-centric approach?
We believe the only scalable solution is to put markup first, as the web intended.
Markup augmented by JavaScript, not embedded in it.
That means your application looks more like this:
<app:header>
<app:toolbar>
<app:editctrls/>
<app:accountinfo/>
<app:support/>
</app:toolbar>
</app:header>
...
And less like this:
/* @flow */
"use strict"
const _ = require("lodash")
const path = require("path")
module.exports = function doSomething(
proj/*: proj$internalApi*/,
options/*: {
code?: string,
}*/
)/*: Promise<Object>*/ {
options = options || {}
...
Here's the essential question to ask about your framework…
When you build your second, third, N'th app will you still be working in code?
TIBET's component consumption model requires no code.
This approach is aimed at helping you reduce your coding effort over time, not keeping you tied to development models that don't scale.
We write JavaScript so you don't have to.
XHTML/XML
Why XHTML/XML?
Well, first of all, there are a lot of business data standards expressed in XML.
A lot of services can potentially be used as-is for direct rendering or data binding without having to alter them in any way. That saves precious time and resources.
All modern browsers support rendering XML directly, meaning you can take XML, inject it into the page (provided it's an XHTML page), and style it with CSS.
Why convert markup to JSON, send it over the wire, and template it back into markup?
Seems like an awful waste of resources to us.
If you have XML services why rebuild them? Why not just call them, gzip the XML for transmission, and render the result or use it as data you bind directly to your UI?
Compressed XML is typically just as small as the equivalent JSON and queryable via XPath, a far more powerful query language than JSONPath.
TIBET is, to our knowledge, the only client stack with full XML support including namespaces and XML-based standards like XPath, XML Schema, and XMPP.
What business value does that serve?
- You don't need to rewrite/overlay services simply to convert XML to JSON.
- You can share and reuse tags and cross-cut features without naming conflicts.
- You can eliminate data conversion overhead by binding I/O directly to XML.
- You can validate your templates, user input, or client/server protocol.
- You can leverage standards-based chat and distributed pub/sub features.
Of course, if you want to use JSON, TIBET also provides full support for JSON, JSON Schema, and JSON Path (as well as a number of other industry standards).
APP vs. LIB
Unless you're building your application from scratch there are two codebases making up your final deliverable: code you write (APP), and code you get from outside sources (LIB).
These two codebases have a lot of differentiating attributes, differences that present both challenges and opportunities.
APP code changes with every edit your developers make.
LIB code changes only when you upgrade versions.
APP code has potentially sensitive information in it such as REST endpoints.
LIB code has no connection to your organization.
APP code has to conform to your coding standards, pass your test suite.
LIB code has its own standards, its own build requirements.
TIBET is designed to leverage the differences between APP and LIB code.
A concrete example of the business value of this mindset is how TIBET loads your app.
Because LIB code is public there's little risk in loading LIB before your users log in. Because LIB code rarely changes it can use browser application caches effectively.
To leverage these differences TIBET's packager builds separate APP and LIB bundles, TIBET's service worker support helps manage browser caching, and TIBET's Loader works in two phases.
During phase one TIBET loads LIB from cache while the user is entering their username and password. There's virtually no network overhead and no appearance to the user of waiting. Once the user has logged in the loader fetches and loads the APP bundle, a much smaller unit of work and one TIBET can optimize through local caching as well.
Looking at APP and LIB code separately and tooling for it allows TIBET to load a larger, more powerful library with virtually no perceived wait time and significantly less network overhead. The result is typical "smaller is better" arguments get turned on their head.
When library size no longer impacts user-perceived startup times, a larger more powerful client is the same asset it is seen to be on the server -- reusable code you don't have to design, develop, and maintain yourself.
Immersive & Immediate
Web browsers natively understand three core "languages": markup (HTML/XML), CSS, and JavaScript.
Each of these technologies is interpreted by the browser on the fly and capable of being manipulated in real time. In other words, they're all capable of immediate editing and display. None require compilers, transpilers, source maps, or other overhead.
Drawing inspiration from the immersive world of Smalltalk development we created Lama™, our immersive IDE, using TIBET itself.
The Lama is specifically designed to take advantage of the dynamic nature of HTML/XML, CSS, and JavaScript as well as TIBET's reflection features to speed your development and eliminate overhead in every way possible.
Unlike the trend in recent frameworks toward technologies you have to compile and reload, the Lama lets you edit, apply, revert, refresh, or save changes you make on either side of the wire without compiling, reloading, or losing your development context.
TIBET lets you build top-down, from the markup in, literally letting you create new tags out of thin air, adding structure, style, and behavior without a single compile or reload.
Want to create a new component out of markup already in the page? Select it in the Lama and ask TIBET to create a new tag from the selected nodes. It's that simple.

With the Lama you work top-down, markup-first, from prototype-to-production
with an unprecedented level of productivity. No compilers. No reloads. Just
results.
Supported Open Source
As you probably know, there's an abundance of open source web frameworks, a handful of supported web frameworks, and not much overlap between those sets.
Most of today's prominent platforms are unsupported.
They're popular, powerful, and often authored by prominent companies…
But there's a catch:
The core business for today's prominent platform authors is not frameworks.
They don't "back them"; they merely authored them.
There's no SLA. You can't call the vendor.
As a result they're free to abandon them, and you.
A perfect example is Google's Angular1 to Angular2 transition, a change that stranded Angular1 projects on a now-moribund platform.
Abandoned frameworks and approaches are nothing new…
Google has gone through Closure, GWT, and Angular1. Today's offering is Angular2+. The jury's still out on Dart and Polymer.
Yahoo! walked away from both YUI and Mojito.
Facebook has changed React repeatedly both technically and in terms of licensing.
With WebAssembly and WebComponents on the horizon there'll be even more churn as these companies compete in their core business: advertising.
Yes.
Advertising.
The scale at which the Googles and Facebooks of the world operate is such that miniscule improvements in performance can affect millions if not billions in revenue.
Those changes would never cause you to abandon your chosen platform, the incremental value would be impossible to measure or recoup.
That's not true for them. They can, have, and will continue to abandon platform after platform. There's too much at stake for them not to.
We're different.
Since 1999 our only business has been the design and development of business web applications and tools.
This is what we do.
It's all we do.
When we say TIBET is supported we mean it; our business and your project depend on it.
Technical Good Parts
TIBET breaks new ground in a lot of areas, the most visible of which are perhaps TIBET's immersive development environment, the Lama, and TIBET's tag-driven shell (TSH), tools which dramatically reduce the need for JavaScript coding.
Here we outline five of the less visible technologies in TIBET, a few of the hidden gems which further differentiate TIBET from other web frameworks.
Multi-Frame MVC
As a framework specifically designed for applications, not publications, TIBET makes use of a unique multi-frame design that isolates your code and data from your UI components, a structural foundation specifically optimized for true MVC and MVVC architectures.
In TIBET, all library and application code loads into what we call "the code frame" while your UI renders and interacts with "the UI frame".
There's only one code frame but applications can have multiple UI frames (e.g. multiple screens in a wizard) and swap between them, instantly sharing code and data across application screens in a true MVC/MVVC fashion.
Thanks to this code-frame design your code is loaded and parsed once, regardless of how often you redraw your UI, giving you the freedom to flush your UI without losing the current code or data context.
Because UI frames are completely independent you can inject screen-specific framework code, scripts, styles, and other components without conflicting with TIBET. A small "hook file" script connects your UI to logic running in the code frame to each UI frame you use.
The result of TIBET's multi-frame design is an architecture which blends the efficiency features of single-page designs with the flexibility typical of multi-page designs.
For example, during startup TIBET's Loader loads library code and resources into the code frame while displaying feedback on a login screen or progress bar in the UI frame.
As an aside, TIBET's approach to resource loading does not require complex JavaScript boilerplate and does not suffer from circular dependency problems often found with other more implicit packager/loader approaches. At the same time, the Loader captures metadata which is invaluable for packaging, testing, and immersive development.
Leveraging TIBET's multi-frame design, the loading process allows you to load library and application assets separately, to load assets in parallel with logins, to patch running code with incremental updates, to dynamically load additional modules, to visualize load progress, to pause after loading but before UI activation, and much more.
While many frameworks claim to be "single-page", only TIBET is architecturally framed to support MVC/MVVC applications with maximum efficiency.
OO + Traits
Simply put, TIBET has the most powerful code-reuse feature set available.
With support for full type inheritance, composable traits, properly executed call-next-method semantics, a true meta-object protocol, and full reflection TIBET is one-of-a-kind.
Best of all, TIBET's OO subsytem is implemented in 100% pure JavaScript, requiring no compilers, transpilers, source maps, or other unneccessary overhead.
What's that all mean?
In business terms it means you don't need your team to learn yet another language or abandon the classical OO development skills they've already become proficient with.
TIBET implements the OO features your existing Java, Ruby, C#, or Python OO programmers are familiar with while adding new features thanks to full type inheritance and composable traits.
In technical terms it means TIBET supports design patterns and tools that are difficult, if not impossible, with other approaches.
Neither ECMA6+ or TypeScript support multiple inheritance or traits. Both have severely limited reflection.
These limitations mean your designs must adjust to fit the language rather than the problem.
TIBET lifts those restrictions, freeing your design.
TIBET helps you keep code organized, maximizes reuse, minimizes design limitations, and does it all without requiring new languages, new compilers, or perhaps most importantly, new developers.
Tags, URIs, Events
A key aspect of simplifying any kind of development is minimizing the number of concepts you need to master.
With TIBET we've done this by focusing on tags, URIs, and events; three things all web developers have to master regardless of their framework choice.
Tags
Web authoring starts with markup.
You can't develop effectively for the web without knowing and using HTML.
Tags are the fundamental unit of functionality, "the quantum of web development" as we say.
TIBET's Tag System is designed with a component consumption model that focuses on no-code, pure markup authoring.
While developers of new tags may write JavaScript, consumers of tags typically use them without writing a single line of code.
Authoring via TIBET tags relies on the same skill set needed for successful HTML authoring, a solid grasp of elements, attributes, and CSS.
<app:employeeTable
tibet:ctrl="EmployeeListController"
bind:io="urn:tibet:employeeList"
on:click="EmployeeClick"
/>
TIBET tags, like their HTML counterparts, have one or more DOM elements
which result from their use. Accessing any of these elements via TIBET's query APIs will return you an instance of a
TP.core.Node
subtype specifically matched to that element.
The TIBET difference is that the instance you receive is a member of a true type which can be extended, subclassed, customized via traits, or tested using the same powerful OO infrastructure available to all TIBET types.
URIs
Whether you're a consumer accessing a web site or a developer accessing a REST endpoint, URIs are the standard addressing model of the web. TIBET lets you use them extensively.
TIBET's URI types provide a well-understood interface for working with both remote and local data within TIBET applications. Accessing a remote resource is as easy as:
const response = await '~/tibet.json'.asURI().getResource();
APP.info(response.getResultText());
Once you have a URI instance you have access to the resource's data, allowing you to snapshot, edit, rollback (undo), sync, PATCH, PUT, or otherwise manage the resource.
All data-related operations leverage TIBET URIs and their Content types.
You can address local UI and data, essentially any TIBET object, using
W3C-standard URN syntax. TIBET types, for example, are addressable via
urn:tibet:{typename}
.
You can assign any object to a URN and acquire it later via that URN from anywhere in TIBET, providing a standards-based form of client-side resource identifier. TIBET URN instances are often leveraged as ValueHolders for data binding or other shared data design patterns. (See TIBET Essentials #3.)
TIBET's data binding syntax relies exclusively on URIs and URNs to define the sources and sinks used for all binds. URI-addressible XML, JSON data, and JavaScript objects combined with XPath, JSONPath, or CSS queries gives you a standards-based syntax for all binding operations.
Events (Signals)
The three things web applications communicate with most: the user, the browser,
and the server, all operate asynchronously. As a result, all JavaScript
developers must become proficient at handling asynchronous notifications:
click
events, XHR states, onmessage
callbacks, etc.
Via TIBET Signals you can respond to UI events,
communicate with a web socket or worker thread, Request
services from a TIBET
Service
, raise or handle Exceptions
, respond to Route, State, or object
Change notifications, update data bindings, and more using a single conceptual
model.
Signaling and signal handling is the common thread running through virtually all of TIBET, unifying, simplifying, and de-coupling your development processes.
More than any other framework, TIBET lets you work primarily with tags, URIs, and events, helping minimize conceptual complexity and onboarding overhead.
Responder Chains
There are a number of unique and/or powerful features to TIBET's signaling system:
- Signals can be either instances of a Signal type or simple Strings,
- Both signal firing and signal handler lookup are "strategy" based,
- Signaling can traverse Signal supertypes in the hunt for handlers,
- Routes, state changes, and other events push/pop the controller stack,
- All signaling conceptually follows a "responder chain" during lookup.
There are a lot of implications to these features but we're going to focus on perhaps the most powerful implication -- the virtual elimination of anonymous handler registration.
DOM Firing
Assume the following markup:
<html>
...
<body>
<div class="help-panel">
<form>
<button class="help-button" id="help-button">Help</button>
</form>
<div>
</body>
</html>
If the user clicks our help-button
the resulting click event will traverse:
document -> html -> body -> div -> form (capture phase)
button (at-target phase)
form -> div -> body -> html -> document (bubble phase)
In most frameworks for a handler to be invoked it must be explicitly added to the target DOM node. This can only happen after the node exists. When the node is destroyed the listener must be removed to avoid leaks or multiple event notifications. As a result, event listeners must be added/removed every time your DOM or document is redrawn.
Responder Firing
Now let's look at a slightly modified version of our earlier markup:
<html>
...
<body>
<div tibet:ctrl="help:panel">
<form>
<button tibet:tag="help:button" id="help-button">Help</button>
</form>
<div>
</body>
</html>
In this version instead of class
attributes we've got a tibet:ctrl
attribute on our div and a tibet:tag
attribute on our button. Everything
else is the same.
Again, let's imagine a user clicks the help-button
.
TIBET's responder firing traverses a very different chain of objects:
ControllerStack -> help:panel (capture phase)
help:button (at-target phase)
help:panel -> ControllerStack (bubbling phase)
With TIBET the responder chain is sparse, focusing entirely on elements that
have tibet:tag
(tag type) or tibet:ctrl
(controller) attributes. In essense
just your widgets and their optional controllers are checked for handlers. The
rest of the DOM is opaque.
The shift from a DOM focus to a "responder" focus is significant.
defineHandler
In TIBET's responder model the computed responder chain isn't made up of DOM nodes, it's composed of tag and controller types.
By moving handler registration to types instead of DOM nodes there's no cycle of add/remove listener overhead, no chance for leaks or duplicate handler registrations, and we pick up the ability to use inheritance, traits, and callNextMethod as needed.
APP.help.button.Inst.defineHandler('UIActivate', function(signal) {
APP.info('help:button -> ' + signal.getSignalName());
});
With the defineHandler
operation above we ensure activation of any
<help:button/>
will automatically invoke our handler.
There's no need to observe or ignore, no potential for leaving listeners attached to DOM nodes, and no option for scattering anonymous event registrations in files that are detached from the component they serve.
If we want to alter the Signal for a specific instance of button we can adjust
that in markup via on:
and define a listener for that Signal instead:
<button tibet:tag="help:button" id="help-button" on:click="Help">Help</button>
APP.help.button.Inst.defineHandler('Help', function(signal) {
APP.info('help:button -> ' + signal.getSignalName());
});
On the other hand if we want to specialize how a particular instance of a tag
might respond we can add a tibet:ctrl
attribute and point to a specific
controller type for that tag:
<button tibet:tag="help:button" id="help-button" tibet:ctrl="HelpController">Help</button>
TIBET's responder design eliminates boilerplate registrations, reduces potential leaks, and self-organizes component/controller methods yielding cleaner code and less of it.
Win win win.
Object Testing
To our knowledge no JavaScript frameworks test from an object-oriented perspective other than TIBET. We think the implications are pretty big.
Without using an OO-based testing approach:
- You lose the ability to fully test inheritance and composition effects.
- Your tests quickly become "detached" from any specific target object(s).
- Your test coverage figures may not reflect testing as much as touching.
- Testing tends to become an independent process, not an immersive one.
TIBET overcomes these problems by focusing on testing objects, which also means testing tags and hence "pages" since pages in TIBET are just tags. TIBET's testing therefore spans from unit tests to functional and integration tests without seams.
Inheritance/Trait Testing
A fundamental presumption in object-oriented languages is that instances of a type should behave consistently with instances of their supertypes.
This implies tests you write for your supertype should pass for instances of any subtype of that type. If they don't then you've created a subtype that violates the presumption. Restrictive subtyping may be "ok" if you intend it, but only OO-aware tests can warn you when you didn't.
Detached Tests
In TIBET your tests are always associated with an object, typically a type, prototype, or method, which is the subject of the test. TIBET's test definition API ensures each test you write is attached to a specific target.
Leveraging TIBET's reflection APIs on possible targets means:
- You can ask any object to run its tests. Every object can have 0-N suites.
- An object can ask for inherited tests and run them in addition to its own.
- Reflection tools can tell you which objects have tests (aka test coverage).
Test Coverage
Most coverage analysis tools directly or conceptually wrap each function in your code to capture call information. Unfortunately, simply knowing your tests indirectly called a function doesn't mean that function has been tested, only that it's been touched.
In TIBET you associate tests with objects. JavaScript functions are objects. TIBET leverages this feature of JavaScript to let you assign tests directly to the functions they test. Thanks to reflection, coverage statistics in TIBET can tell you not only whether something was called but whether you actually wrote tests for it, a far more meaningful measure of "coverage".
Immersive Testing
True test-driven development, a write-failing-tests-first approach, can be a challenge for many teams and developers to use effectively.
TIBET instead encourages a "test early, test often" approach by supplying both CLI and Lama-based tooling to support interactive, immersive testing.
You can test objects in the Lama just by selecting them via the Halo or Inspector and asking to run their tests. If no tests exist you can add them interactively directly in the Lama, removing friction and artificial barriers between developing and testing.

From the Lama you can add, edit, and run tests across your application or against a specific target object, allowing you to work iteratively through a cycle of creating new tags, adding new tests, and running those tests as you work top-down through your application.
Summary
If you made it this far you probably recognized the problems TIBET was built to solve as problems your own projects may have struggled with.
Hopefully this review of TIBET's good parts helps you see how TIBET solves those problems without requiring you to either abandon JavaScript or write too much of it.
Now we'd like to invite you to take the next step, install TIBET and experience the TIBET difference for yourself. We think you'll love it.