TIBET Logo

TIBET Conventions

Conventions

wins

  • Create working code more quickly.
  • Create maintainable code more naturally.
  • Onboard new developers and other team members faster.
  • Support creation of smarter development tools.
  • Help support to be more focused and effective.

contents

concepts

cookbook

Files
Names
Coding
Simplifying

code


concepts

Convention over configuration. It's what set Rails apart and a central difference between frameworks and libraries (the other being frameworks tend to call your code, not the other way around).

Frameworks with strong conventions are often referred to as "opinionated". We prefer to think in terms of "organizing". A good framework helps organize your code and organized code is code that is easier to understand and maintain over time.

Large applications and long-lived applications will, in the absence of strong organizing principles, become difficult to maintain over time. Good conventions provide a set of organizing principles, helping you build maintainable code naturally.

TIBET's conventions center around a few key principles:

  • Separate library and application concerns. TIBET treats library code and application code separately including rooting them on TP vs. APP and loading them in separate phases.
  • Names matter. If two things are the same they should have the same name. If they're similar they should have similar names. If they're different they should have different names. Nothing is more confusing than poor or inconsistent names.
  • Patterns matter. Names should follow predictable patterns so programmers and tools have a good chance of guessing and/or generating them. When you can guess what something will be named the result is a framework you think of as "intuitive".
  • Late bind all the things. Alan Kay, who coined the term Object-Oriented, said it consisted of three things: messaging, encapsulation, and "extreme late binding of all things". TIBET is heavily biased toward dynamic lookup patterns which help support API level "late binding".
  • Metadata -> Metaprogramming. Lastly, TIBET focuses heavily on capturing metadata for use in reflection, method dispatch, and tooling. Many of TIBET's conventions and/or APIs are a direct result of a desire to capture or leverage metadata.

LateBindAllTheThings

In support of these principles TIBET uses a number of conventions and coding standards that are specifically designed to speed development, enhance maintainability, and improve tooling.

You should be familiar with TIBET's coding standards as outlined in these documents:

You should follow JavaScript: The TIBET Parts guidelines without exception:

  • Don't use functions as types.
  • Don't use typeof or instanceof.
  • Don't use new.
  • Don't access a property directly.
  • Don't use {} as a hash/dictionary.
  • Don't use for/in.

TIBET provides more powerful replacements, namely:

  • defineSubtype and addTraits
  • isType, isKindOf, isMemberOf, etc.
  • construct (a pairing of alloc and init)
  • get() and set() methods with dynamic method lookup
  • TP.core.Hash (TP.hc) and its collection API support
  • TIBET's perform, collect, select, detect, reject, etc.

You should be familiar with TIBET Signaling and Routing as outlined here:

You should also read The Zen Of TIBET which discusses TIBET's design principles.

Other conventions and patterns we've found useful in creating maintainable code are outlined below. You should conform to these conventions to be successful with TIBET.


cookbook

Files

Keep types in their own file

While not required, TIBET will work more effectively if you avoid having more than one type per file. The TIBET CLI commands such as tibet type will automatically generate new files for types you create and update your applications load package to reference these files automatically.

TIBET's rollup and packaging tools will automatically concatenate these files to avoid any extra HTTP overhead that might otherwise occur from having numerous type files.

Keep type CSS in its own file

For easier authoring it's better to keep CSS specific to a particular tag type in a unique file named to match the type. As with many other file-level operations the tibet type command will automatically generate files to support this convention.

TIBET's rollup and resource inlining tools will automatically combine these files and/or inline them to eliminate any HTTP overhead that might otherwise occur as a result of keeping your type's CSS in a separate file.

Consider using "component bundles"

To help with potentially sharing tags and other components across projects via the tibet publish and tibet install commands, consider keeping all assets and logic related to your tags in separate subdirectories of your ~app_src directory.

Names

Use the source :)

The full TIBET library with all extensions, addons, and optional namespaces, comprises over 330k lines of heavily commented code (a 55/45 code-to-comment ratio). That's a lot of source text to draw upon for existing patterns, and names.

If you're creating new code and not sure what to name something check the existing TIBET source code. There's a lot of existing effort behind naming in the TIBET code. If at all possible try to leverage that when creating new code.

tibet reflect and tibet apropos are particularly useful for this purpose.

Use TIBET's method name pattern

TIBET uses a common pattern for naming functions and methods, one largely inspired by Smalltalk and Objective-C, languages which provide for reasonably "literate" API design.

The pattern is simple and relies on using the parameters to help you arrive at a method name which helps you remember what to pass where.

For example, TIBET has a collection API method atPut. This method name is the result of following our naming pattern, which begins with examining the known parameters.

Our method parameters in this example consist of an index and a value to place at that index. In Smalltalk/Objective-C our method would resemble at: index put: value.

To convert at: put: to valid JavaScript we take the word portions and concatenate them in camel-case form so that at: index put: value becomes atPut(index, value).

TP.core.Hash.Inst.defineMethod('atPut',
function(anIndex, aValue) {
...
});

The goal is to end up with method names that not only tell you something about what the method does, but which also help remind you of the parameter order. Just invert the process. If you split atPut on word boundaries you arrive back at at: x put: y, which makes it easy to remember where index and value go.

Use TIBET's primitive name pattern

The TIBET platform uses several hundred lower-level functions to create an insulating layer between TIBET and the underlying browsers in which it runs. We call these functions "primitives" after the Smalltalk term for similar low-level C interfaces.

TIBET primitives almost universally begin with an object name in lower case, something like 'element', 'attribute', 'node', etc. which identifies the type of the first parameter. The remainder of the name tends to follow the TIBET convention for method names.

TP.definePrimitive('nodeGetDocument', function(aNode) {...});

You can use awareness of this pattern to help you find useful functionality. For any APP-level primitives you create we recommend following a similar convention.

Coding

Use the source (part deux)

One of the central tenets of TIBET is that the library should provide 80% of your functionality and you should provide the 20% specific to your application.

If you find yourself writing a lot of JavaScript it may be that we've overlooked something, but it also may be that you haven't explored the existing source thoroughly enough.

Commands like tibet apropos and tibet reflect can be helpful in exploring the library for objects, methods, and primitives that may already do what you need.

Use TIBET coding standards

See JavaScript: The TIBET Parts and TIBET Coding Standards for a detailed discussion of the baseline standards your TIBET code should follow.

In extreme form the quick summary of necessary changes is:

  • Don't use functions as types.
  • Don't use typeof or instanceof.
  • Don't use new.
  • Don't access a property directly.
  • Don't use {} as a hash/dictionary.
  • Don't use for/in.

TIBET provides much more powerful replacements, namely:

  • defineSubtype and addTraits
  • isType, isKindOf, isMemberOf, etc.
  • construct (a pairing of alloc and init)
  • get() and set() methods with dynamic method lookup
  • TP.core.Hash (TP.hc) and its collection API support
  • TIBET's perform, collect, select, detect, reject, etc.

Additional standards such as placing your method comments for better reflection and tooling and numerous other hints are also described in those documents.

Simplifying

Use TIBET's tools to simplify development

As a full-stack solution that includes both a full suite of command line tools and a browser-based IDE, TIBET provides you with a lot of tooling to help simplify your development.

For example, rather than creating new files yourself use the tibet type command to add new classes to your application. This will automatically create the new type file with pre-built logic as well as any associated asset files such as a default template file and style sheet. The tibet type command will also automatically update your application's load package to make sure the new type is loaded correctly. If your application is running it will also automatically patch in the new type, template, and style sheet without reloading.

Using the TIBET Sherpa can be even simpler. For example, creating a new tag is as easy as drag-and-drop. After filling in a simple dialog the tibet type command is run for you and the new assets are automatically patched into your running application.

Use the APP root to separate application code

Unlike other libraries or frameworks, TIBET relies on a strong separation between framework code and application code. This separation is leveraged in tooling, caching, and a number of other places in TIBET.

A good design pattern is to modularize between components with different rates of change. For example, you're changing your application code daily but you may only update your TIBET library once a quarter. Keeping the two separate helps reinforce not only a clean boundary of responsibility but one that can benefit you in other ways.

In TIBET, all application code is expected to be rooted on a single global, APP, which is provided as part of the TIBET framework. TIBET's CLI commands support this convention whenever you use them within a project context. If you use the tibet type command either from the CLI or via the Sherpa your new type will normally be rooted off APP.

As one example of the benefits of the APP vs. TP approach, by separating your code from the framework TIBET lets you reload application code without forcing a reload of TIBET framework code, dramatically reducing load times and network overhead.

Use defineHandler to simplify event handling

One of the more powerful features of TIBET is what we call the "responder chain", the set of implicit event handlers in place for any signal which occurs.

As an example, when you click on a button in your UI TIBET will automatically create a chain consisting of the button itself, any tibet:ctrl on that button, and any custom tags or controllers in the button's ancestor DOM chain. TIBET will also automatically include your Application instance and its controller stack in the responder chain.

The resulting responder chain is then checked, type by type, for any handler methods which are suitable given the origin of the event, the nature of the event, and the current application state. This is all handled automatically, you never have to explicitly observe or ignore individual UI elements.

Use TIBET patterns to simplify code

From get and set to callNextMethod and callBestMethod, TIBET is full of prebuilt patterns and method lookups that can dramatically simplify coding.

Creating a new type and want to initialize it on startup? Implement initialize.
Need to be able to build instances from hashes? Implement fromTP.core.Hash. Want to parse strings to create instances? Implement parse.

TIBET pattern methods cover a wide range of functionality, usually in pairs:

  • as/from
  • isa/validate
  • parse/format
  • get/set

Leveraging these and other common TIBET methods allow your objects to fit quickly into the overall TIBET ecosystem.


code

Look for examples of TIBET's conventions throughout the codebase.