Design is a very common concept that is generally understood to form a plan or framework for something that will be done beforehand. (Oxford English Dictionary), design is a piece of art, system, hardware or more things woven into a line. Software design, especially as a sub-class API design for software design, is the same. But API design often pays little attention to software development, because writing code for other programmers is more important than applying UI design and end-user experience.
But API design, as the public interface provided in our own library, can show some of the features and functions of our library to the developers calling our code, so API design is as important as UI design. In fact, both are basic ways for the app to provide a better user experience. The app UI is an important place in user UX, and the App API is a developer's UX. Therefore, the application API design should be given the same level of consideration and attention as the interface we provide to the user. Just as we focus on the efficacy, simplicity and beauty of the UI, we should also evaluate the effectiveness of the API, simplicity and the beauty of the code!
API design--javascript API design content, presents the only challenge to all developers, whether or not you are developing a public library or an internal library. The dynamic nature of JavaScript, the anonymity of the library users and the ambiguity of the requirements present a daunting challenge to the API designers. However, there is no shortcut to a good API design, but it is possible to extract some design guidelines from some of the most popular JavaScript libraries today!
API design: The Battle of Angels and Demons
The poor design of the JavaScript API will bring a high cost to the developers who use your API. Poor design can lead to waste, and developers who use your API will waste time trying to figure out your interface, while API developers are wasting time dealing with growing demands and solving users ' confusion. However, almost all APIs were originally developed in order to be able to extract the same functionality, make it easy to call and save time. But poorly designed APIs can make your library users and you wonder, can these libraries really save time?
Excellent API design, on the one hand, completed the extraction of the target, but also to achieve self-description. When an API is well designed, users can quickly and intuitively complete their work without the need to constantly use documents or continue to access support or answer websites. You can also save time for library developers by encapsulating some of the features that developers need to spend a lot of time developing. Good design not only saves developers time, it can make them look smarter and more responsible. Also helping your users look smart and competent will make you look even more awesome!
API design is especially important for JavaScript
Regardless of programming language or framework, API design is important, and the importance of API design is higher for JavaScript than in many other languages. First, as a dynamic and late-bound language, JavaScript does not have a compiler to implement a safety net or detection unit function, so JavaScript can not find errors in your code. Linting or inspection frameworks such as JSLint and Jshint can help us. The functionality of these frameworks can indicate some common errors in JavaScript, but when we use the API, they are not able to find JavaScript errors.
It all depends on you, you can develop a well-designed API that can help your users fall into a well-known "success pit", which means that your library is comfortable and familiar to developers, while also providing positive reinforcement and confidence when developers interact with your code.
The best example of "falling into a successful pit" is jquery using CSS selector syntax to get DOM elements. For example, if I want to get all the article elements with a class name, I can do this using jquery:
1 |
$( "article.blogPost" ).fadeIn(); |
The selector article.blogpost and the following shows the use of the exact same syntax, which is by no means accidental!
12345 |
article.blogPost { border-radius: 10px; background-color: salmon; box-shadow: 0px 0px 10px 2px #ccc; } |
The jquery selector engine was designed to enable me and other developers to enable me to interact with the CSS selector's understanding and its engine. As it turns out, if jquery needs me to use a new, form-specific syntax for a particular purpose, I will lose speed, apparent and efficiency.
We can get inspired from these frameworks, such as jquery, or other frameworks, and apply these inspirations to our designs. However, the inspiration is not plagiarism, there is a degree of problem, anyone who has designed the API if it is only based on the ideas of others, whether good or bad, he will inherit. If we apply the guidelines obtained in good JavaScript to other areas, we can develop frameworks with good APIs that can be used in any situation.
Excellent design tips for JavaScript APIs
Although software does not have a visual evaluation standard similar to painting or architecture, we tend to use adjectives like physical entities to describe software quality. For example, it is not uncommon to use "elegant" and "beautiful" to compliment the software. If it is reasonable to describe the software interface with adjectives similar to physical entities, then of course you can use the same principles to evaluate the software design.
In this section, four popular design principles from the art world are extended to the API design:
- Harmonious and consistent
- Balance
- Symmetric
- Focus Highlights
For each principle, one or more examples are listed to illustrate how the popular JavaScript Library API design follows these principles.
Principle 1: Consistency & coordination
In works of art, consistency is an indispensable concept behind a work, or how a designer can make things into a coherent whole. Coordination, on the other hand, is a layout of similar elements of a work, which creates a neat feeling when considering the whole.
For the designer of the API, these principles can be implemented by using similar and/or uniform elements in the class library. Take the kendo UI, a JavaScript framework for creating rich Web applications. The Kendo UI provides a range of UI controls and tools that can be initialized with a simple syntax. For example, if I want to create a tree control (TreeView) from an unordered list, I only need to call the following methods:
1 |
$( "ul.tree" ).kendoTreeView({ /* Configuration goes here */ }); |
Kendo UI Tree Component
If I want to create a panel panelbar from a list, I just need to change it slightly to a different calling method.
1 |
$( "ul.panel" ).kendoPanelBar({ /* Configuration goes here */ }); |
Kendo UI Panel Components
The kendo UI uses a consistent kendox syntax for all components to facilitate overall coordination. More importantly, such a design relies on the jquery object to encapsulate a uniform layer of DOM elements, making the design beneficial to all the jquery developers. Millions of developers using a similar "vernacular" (jquery syntax), the Kendo UI can be used successfully across libraries.
Another coordinated case is backbone's [object].extend syntax for creating objects, inheriting and extending backbone's models,views,collections and routers capabilities. You can create a backbone Model with the following code, complete with backbone support, or customize the features I need:
12345 |
var Book = Backbone.Model.extend({ initialize: function () { ... }, author: function () { ... }, pubDate: function () { ... }, }); |
The purpose of unification and coordination is to make the API novice feel familiar and comfortable. By using different features, but with the same syntax or similarity, the API becomes familiar, greatly reducing the burden on developers to use new tools.
Principle 2: Balance
The next principle is to balance the elements so that they do not make a part too heavyweight and cover the other parts and are unstable when used. In art works, balance is the visual weight. Even if it is asymmetric, the balance of asymmetry can still be felt in the work because it follows a certain pattern. In context of the design balance of the API, I specifically refer to the visual weights and predictability of the code (see function). Balanced APIs let people feel that their components belong to each other, they behave the same, or complement one goal in a complementary way. With extensions, APIs can also feel balanced, allowing developers to simply predict and use other APIs. such as Modernizr's property tests, their balance in two aspects, a) attribute names correspond to HTML5 and CSS terms and API names, B) Each property test returns a value of TRUE or false uniformly.
12345678 |
// All of these properties will be ‘true‘ or ‘false‘ for a given browser Modernizr.geolocation Modernizr.localstorage Modernizr.webworkers Modernizr.canvas Modernizr.borderradius Modernizr.boxshadow Modernizr.flexbox |
Accessing a single attribute to tell the developer about the relevant properties to access each of the other properties, the strength of a high-quality API is its simplicity. The balance also ensured that the code I wrote and Modernizr interacted with had the same visual weighting every time I read and write. How I look and feel when I use and access the API, regardless of my routine. On the other hand, if Modernizr adds a Polyfill canvas API, not just the visual weighting of the class library affected by the new API, the scope and purpose of MODERNIZR will be greatly expanded, and I am constrained in predictability when interacting with the API.
Another way to achieve balance is by relying on the developer's familiarity with the concept to obtain a predictable result. A typical example is the jquery ' s selector syntax (the syntax of the jquery selector), which maps the css1-3 selector to its own DOM selector engine:
123 |
$( "#grid" ) // Selects by ID $( "ul.nav > li" ) // All LIs for the UL with class "nav" $( "ul li:nth-child(2)" ) // Second item in each list |
By using a familiar concept and mapping to its own class library, jquery avoids the new selector syntax, and colleagues create a mechanism for new users to quickly apply a class library to production through a predictable API.
Principle 3: Proportionality
The next principle is proportionality, which is used to measure the size and number of elements in a work. Rather than a good API is a small API, proportionality is relative to the size of the use. A proportionate API that matches its API surface to its capabilities range.
For example, Moment.js, a popular date conversion and Formatting class library, can consider it to be proportionate because its API surface is compact, and it matches the purpose of the class library explicitly. Moment.js is used to process dates, and its APIs provide handy features for working with JavaScript date objects:
12 |
moment().format( ‘dddd‘ ); moment().startOf( ‘hour‘ ).fromNow(); |
For a targeted class library, like Moment.js, it is important to keep the API focused and simple. For larger and broader class libraries, the size of the API should reflect the capabilities of the class library itself.
For underscore, as a library of versatile uses, it provides a number of handy functions that are designed to help developers work with JavaScript collections, arrays, functions, and objects. It has much more API than libraries like Moment.js, but underscore is also proportional because each function in the library has its own purpose. Consider the following example, the first two examples use underscore to manipulate the array, and the last to process the string.
123456789 |
_.each([
"Todd"
,
"Burke"
,
"Derick"
],
function
(name){
alert(name);
}); _.map([1, 2, 3],
function
(num){
return num * 3;
});
_.isNumber(
"ten"
);
// False
|
As a library grows, the challenge of maintaining proportions becomes more severe. To ensure that each function and function that is added to the library strengthens the library's purpose, more input is needed. For a large library like the kendo UI, the purpose of extensibility does not mean that we need to add each feature to the library. For a library as large as kendo, functional objects and features should demonstrate their value in order to be included in the library. For example, Kendo UI ' s JavaScript is based on DataSource, which can be used to query and process remote data.
12345678910 |
var dataSource =
new kendo.data.DataSource({
transport: {
read: {
url:
"http://search.twitter.com/search.json"
,
dataType:
"jsonp"
,
data: { q:
"API Design" }
}
},
schema: { data:
"results" }
});
|
At first glance, it seems to be a familiar source of data that feels beyond the basic purpose of the library itself. However, today's site decoration requires dynamic Data support. The introduction of data sources allows the Kendo UI to use a stable, and comfortable paradigm to resolve remote data across the entire library range.
Turning an API into a veritable JavaScript trash drawer is dangerous for an extension of a library, but it's not the only danger for libraries. It's also dangerous to fall into a trap that doesn't allow your API to accompany the library, or to limit the size of your library for some human reason!
One of the best examples of not handling API growth is jquery's jquery or $ function. As well as I have thousands of developers like Jqurey, but its portal approach is a bit messy, from DOM selection to include DOM elements in jquery objects, this method provides more than 11 independent overload options.
For the most part, some features that are not very relevant are hard-shoved into the same API. From a global perspective, jquery is a large library and can be thought of as a reasonable ratio of libraries. On the other hand, when we try to cram a function into a single interface without regard to the library scale, the jquery approach can do the same.
If you find that you are moving an irrelevant trait into a method that already exists, or are thinking of trying to rationalize the addition of a function that is not appropriate for the API, the change you need to make is to loosen the belt and let the library breathe. Your users will be more time-saving when invoking a new function that can describe their name, and will not add a burden to another already existing method.
Principle 4: Emphasizing sex
In works of art, emphasis is placed on the use of contrasts to make one aspect of the work stand out as a focal point. In many APIs, the focus may be the anchor point for a channel or class library primary method. Another example of emphasis can be found in the "link" approach or the fluent API, which highlights the central object of the class library by increasing the emphasis effect. jquery tends to emphasize this object from a number of functional demos:
12345 |
$(
‘ul.first‘
).find(
‘.overdue‘
)
.css(
‘background-color‘
,
‘red‘
)
.end()
.find(
‘.due-soon‘
)
.css(
‘background-color‘
,
‘yellow‘
);
|
For many modern class libraries, another example of emphasis is extensibility: the part that the class Library creator does not provide gives you a tool you can do with your own extensions.
A typical example can be referred to JQuery ' SFN (pronounced "effin") namespace, the general extension point can be done through countless plugins and supplementary class libraries:
12345678910 |
(
function
($) {
$.fn.kittehfy =
function
() {
return this
.each(
function
(idx, el) {
var width = el.width,
height = el.height;
var src=
"http://placekitten.com/"
;
el.src= src + width +
"/" + height;
});
};
})(jQuery);
|
Another example of extensibility is backbone's "extend" function, which we've seen in this article:
123456789 |
var DocumentRow = Backbone.View.extend({
tagName:
"li"
,
className:
"row"
,
events: {
"click .icon"
:
"open"
,
"click .button.edit"
:
"openEditDialog"
},
render:
function
() { ... }
});
|
Extensibility is an emphasis on the one hand because it makes us aware of the fact that existing libraries do not mean that everything is perfect, but also encourage us to expand our own class library. When class libraries support extensions, they not only open up new uses, but also benefit countless developers for general purposes. One of the best examples is the Backbone.marionette framework, a class library that extends to backbone, which aims to "simplify the structure of large JavaScript applications." A class library such as marionette would become very complex and even impossible to implement if it were not a class library extension like backbone.
API design: Not just for library code writers
If you are not the writer of a JavaScript library, but a developer or library of JavaScript applications, you might think that the principles in this article do not apply to you. After all, most of us, when we hear the API, tend to think of third-party libraries, just as I did in the example in this article.
The fact is that the API, as its definition suggests, is nothing more than an interface that provides the isolation capabilities that others take advantage of. Now, let me use an old saying to emphasize the important point: to write the modular JS code is practical, the number of times is not important.
As the class library referenced in this article, you can expose your JavaScript code to other people. Even if the user of your code is a small or internal team--even if you build your own private class library--you don't have to think about the API design principles and implementations of these principles in this article like the authors of a public class library. The advantage of using API design is that even for a single user, it should be designed like a millions of user.
Because the API is designed to represent the user experience of the developer, it is just as important to the end user as the UI design. Just as we can develop a good UI by learning some principles and referring to some good or bad examples, we can learn better API design in the same way. The four principles mentioned in the application, as well as other principles you find yourself, can help you build good APIs and give users a good experience.
Great JavaScript API Design tips