TIBET Logo

TIBET: The Good Parts™

TheGoodParts


With a product as comprehensive as TIBET it can be easy to miss the forest for the trees, to check off features while overlooking the big picture that makes TIBET truly compelling.

With that in mind, we present TIBET: The Good Parts, a nod to the bible of JavaScript best practices and a summary of what we believe sets TIBET apart.

From a business perspective TIBET:
  • creates a scalable "authoring pyramid" for development teams,
  • focuses on markup-first authoring with full XML standards support,
  • separates application and library concerns in a structured fashion,
  • removes impediments to immersive, immediate development flows,
  • is open-source and fully-supported by the vendor that built it.
From a technical perspective TIBET:
  • optimizes single-page MVC applications using a unique multi-frame design,
  • surpasses TypeScript and ES6/7 in inheritance, composition, and reflection,
  • focuses coding on tags, URIs, and events, reducing conceptual clutter,
  • simplifies routing, event handling, and exception handling via responders,
  • unifies interactive unit and integration testing at the object level.



Business Good Parts

We strongly believe TIBET is your best choice for business and government web development, in part because it was specifically designed to be.

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 desktop-class web applications. Yes, TIBET has some cool technology, but that technology was created in response to business, not technical concerns.


Authoring Pyramid

The Authoring Pyramid

Over the years we've spoken with dozens of decision makers about the issues they face with their web projects. In discussing their challenges they never focus on things like "callbacks are complicated", "we need static typing", or "everything would be fine if JavaScript had modules".

In fact, without exception they never mention technical issues at all. On the other hand, they universally complain about one issue: "Hiring good JavaScript coders is impossible."

At first we just nodded in sympathy and kept building versions of TIBET that, you guessed it, required skilled JavaScript coders. Then we face-palmed and started work on TIBET 5.

To address what's been called "the hardest AJAX problem", staffing, TIBET is designed around the concept of an authoring pyramid.

The idea behind TIBET's authoring pyramid is simple: align the skill requirements for TIBET projects with the distribution of UI, application, and framework-level skills in the web.

If there are ~100 UI-level developers for every ~20 application-level developers for every 2 framework-level developers then TIBET projects should require the same distribution of skills or roughly 80% markup and 20% code.

If you can staff 80% of your team from a pool with solid markup/CSS skills and basic JS skills while the rest can be component-level developers but not gurus, ninjas, or rockstars you've dramatically reduced the #1 risk to your projects -- the inability to staff them properly.

Zoom in to TIBET's technical features and you'll see an IDE, a shell, a CLI. Look deeper and you'll see widgets, a tag system, routes, responders. Below that, state machines, exception handling, signaling, and classical OO. Deeper still, hundreds of "primitives" providing platform isolation and portability. More "features" than any other web platform.

Zoom out however and you'll realize your seeing something even more powerful, a set of consciously designed layers: tools built upon tags built upon objects built upon functions; the distinct levels of authoring abstraction making up TIBET's authoring pyramid.



Markup First

Markup First

At last count there were roughly 4.6 Billion-with-a-B indexed web pages. Imagine that. In the last 25 years humanity has collectively authored literally Billions of pages. Now imagine if, instead of using HTML, all of it had required authoring in JavaScript with modules, classes, fat-arrow functions, or JSX. How fast do you think the web would have grown?

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?

When faced with building multiple applications we believe the only scalable solution is to put markup first, as the web intended, markup augmented by JavaScript, not embedded in it.

What does markup-first mean in concrete terms?

It 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 || {}
...

If you're only building a single application the difference might not be too noticeable, initially you'll be building up your component library.

Here's the essential question though...

When you build your second, third, fifth application will you still be working in code?

TIBET is designed around a component consumption model that uses no code; an approach aimed at helping you reduce your coding effort over time, not keeping you tied to development models that won't scale in the enterprise.

As our motto says: "We write JavaScript so you don't have to™".

While you can interpret that motto to mean you can outsource your JavaScript development to Team TIBET, and we certainly welcome that opportunity, it's really intended to remind you the TIBET platform is specifically designed to reduce your dependency on JavaScript.

XHTML/XML

Why XML? Well, first of all, there are a lot of existing standards expressed in XML. A lot of legacy services that could 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.

A little-known fact is that modern browsers support rendering XML, meaning you can take XML, inject it into the page, and style it with CSS. So if that's possible why convert it to JSON, send it over the wire, and template it back into...uh...markup? Seemed like an awful waste of resources to us. If you have XML services why rebuild them? Why not just call on them, gzip the XML on the wire, and render the result or use it as data you bind to your UI?

TIBET is, to our knowledge, the only client framework 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 existing services simply to convert XML to JSON.
  • TIBET tags are namespaced so you can share and reuse without naming conflicts.
  • XPath binds your UI directly to XML nodes for both read and write operations.
  • XML Schema can validate your templates, user input, or client/server protocol.
  • XMPP lets you leverage standards-based chat and distributed pub/sub features.

XML is mature, standardized, widely used, and heavily tooled. XML is automatically parsed by every browser, can be templated via XSLT, supports direct rendering and styling, can be commented, preserves data order, and compresses efficiently for transmission to the client. With TIBET it can also support bi-directional data binding and change notification.

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

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 appcache command helps manage browser caching, and TIBET's Loader works in two phases.

During phase one TIBET loads LIB from appcache 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 we're working to 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. 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 library becomes the same asset it is seen to be on the server -- reusable code you don't have to design, develop, and maintain yourself.

APP vs. LIB awareness isn't just a packager feature, it's a feature woven into every aspect of TIBET from the CLI to the Sherpa and it's another feature that makes TIBET unique.



Immersive

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 our IDE, the Sherpa™, using TIBET itself. The Sherpa 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 wait to compile and reload, the Sherpa 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. You can also create and run new unit and UI tests in-situ.

Instead of writing code, compiling it, letting it reload, and only then seeing it for the first time, 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 Sherpa and ask TIBET to create a new tag from the selected nodes. It's that simple.

With the Sherpa you work top-down, markup-first, from prototype-to-production with an unprecedented level of productivity. No compilers. No reloads. Just results.



Supported

Supported Open Source

As you probably know, there are numerous open source web frameworks, a handful of supported web frameworks, and not much overlap between those sets.

Most of today's prominent frameworks are unsupported. They're popular, powerful, and often authored by prominent companies...but there's a catch.

The core business for today's prominent framework 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 the Angular1 to Angular2 transition, a change so dramatic it stranded Angular1 projects on a framework they'll have to port off of sooner or later.

The thing is, abandoned frameworks are nothing new.

Yahoo! walked away from both YUI and Mojito. Similarly, Google has gone through Closure, GWT, and Angular1. The jury's still out on Dart and Polymer. Today it's Angular2+ but with WebAssembly and WebComponents on the horizon there'll almost certainly be more churn and more license pain as these companies compete in their core business: advertising.

Technical Pursuit is 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 Sherpa™, and TIBET's revolutionary 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.



Framing

Multi-Frame MVC

As a framework specifically designed for single-page applications 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 scripts, styles, and other components without conflicting with TIBET. A small "hook file" script connects your UI to logic running in the code frame.

The result of TIBET's multi-frame design is what you might call "multi-page single-page" applications, an architecture which blends the efficiency features of single-page designs with the flexibility typical of multi-page designs.

During startup TIBET's Loader loads application code and resources into the code frame while displaying feedback on the loading process or a login screen in the UI frame. This approach allows code to load "invisibly" while the user enters account and password information, one more benefit of TIBET's multi-frame architecture.

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

OO + Traits

Simply put, TIBET has the most powerful JavaScript OO feature set available, exceeding the capabilities of ECMA6, TypeScript, and other web frameworks.

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 (ECMAScript 5), 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 or C# 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 type 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.

In short, TIBET helps you keep your code organized, maximizes reuse, minimizes design limitations, and does it all without requiring new languages, new compilers, or, perhaps most importantly, new developers.



W3C

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

You can't develop for the web without knowing and using HTML. Web authoring starts with markup. With TIBET we leverage tags as the fundamental unit of functionality.

The TIBET Tag System lets you create new tags with ease and treat them as reusable bundles. While developers of new tags may write JavaScript to support a new tag, consumers of those tags can often 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"
/>

Each tag you write ultimately translates into a node in the DOM. <button>Hi</button>, the button "tag" for example, becomes a button element in the DOM.

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.

TIBET's node types provide a rich API for interacting with nodes to set/get content, add/remove attributes, or perform other tasks. TIBET's node instances also give you access to TIBET's other subsystems such as tag processing, templating, data binding, and more.

The critical difference in TIBET is that the wrapper 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:

'/tibet.json'.asURI().getResource().then(function(result) {
    TP.info(result);
});

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 your data-related operations leverage TIBET URIs and their helper 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.

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.

To simplify and unify interactions with these elements while maintaining loose coupling between application components TIBET relies on an integrated signaling subsystem.

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.

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.



Responders

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 and no chance for leaks or duplicate handler registrations.

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.



Testing

Object Testing

To our knowledge no JavaScript frameworks test from an object-oriented perspective other than TIBET. We think the implications of that oversight are pretty big:

  • 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.
  • TIBET's 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 Sherpa-based tooling to support interactive, immersive testing.

You can test objects in the Sherpa 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 Sherpa, removing friction and artificial barriers between developing and testing.

Halo Testing

From the Sherpa 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.

The Pup

Contact us for more information or to discuss how we can assist you.