Design ist ein sehr verbreitetes Konzept, das im Allgemeinen als die Erstellung eines Plans oder Rahmens für etwas verstanden werden kann, das getan werden soll. (Oxford English Dictionary) ist Design ein roter Faden, der Kunst, Systeme, Hardware und mehr miteinander verbindet. Das Gleiche gilt für Softwaredesign, insbesondere API-Design als Unterkategorie des Softwaredesigns. Beim API-Design wird der Softwareentwicklung jedoch oft wenig Aufmerksamkeit geschenkt, da das Schreiben von Code für andere Programmierer zweitrangig ist gegenüber dem UI-Design der Anwendung und der Erfahrung des Endbenutzers.
Aber API-Design als öffentliche Schnittstelle, die in der von uns selbst geschriebenen Bibliothek bereitgestellt wird, kann Entwicklern, die unseren Code aufrufen, einige Features und Funktionen unserer Bibliothek zeigen, sodass API-Design genauso wichtig ist wie UI-Design. Tatsächlich sind beides grundlegende Möglichkeiten, wie Anwendungen eine bessere Benutzererfahrung bieten können. Die Anwendungs-UI nimmt eine sehr wichtige Position in der Benutzer-UX ein, und die Anwendungs-API ist die UX des Entwicklers. Daher sollte dem Design der Anwendungs-API das gleiche Maß an Aufmerksamkeit und Aufmerksamkeit gewidmet werden wie der Schnittstelle, die wir unseren Benutzern bereitstellen. So wie uns die Funktionalität, Einfachheit und Schönheit unserer Benutzeroberfläche am Herzen liegt, sollten wir auch die Funktionalität, Einfachheit und Schönheit unserer APIs und unseres Codes bewerten!
API-Design – Der Inhalt des JavaScript-API-Designs stellt alle Entwickler vor einzigartige Herausforderungen, unabhängig davon, ob Sie eine öffentliche Bibliothek oder eine interne Bibliothek entwickeln. Die dynamische Natur von JavaScript, die Anonymität der Bibliotheksbenutzer und die Mehrdeutigkeit der Anforderungen stellen API-Designer vor große Herausforderungen. Allerdings gibt es keine Abkürzungen für ein gutes API-Design, aber es ist möglich, einige Designprinzipien aus einigen der beliebtesten modernen JavaScript-Bibliotheken zu extrahieren!
API Design: Der Kampf zwischen Engeln und Dämonen
Ein schlechtes Design Ihrer JavaScript-API führt zu hohen Kosten für die Entwickler, die Ihre API verwenden, und für Sie. Schlechtes Design führt zu Verschwendung. Entwickler, die Ihre API verwenden, werden Zeit damit verschwenden, Ihre Schnittstelle herauszufinden, und API-Entwickler werden Zeit damit verschwenden, sich mit der steigenden Nachfrage zu befassen und Verwirrung bei den Benutzern zu beseitigen. Als jedoch fast alle APIs ursprünglich entwickelt wurden, waren sie darauf ausgelegt, dieselben Funktionen zu extrahieren, Aufrufe zu erleichtern und Zeit zu sparen. Aber eine schlecht gestaltete API macht Ihre Bibliothek zu Benutzern und Sie fragen sich, ob diese Bibliotheken wirklich Zeit sparen?
Ausgezeichnetes API-Design vervollständigt einerseits das Ziel der Extraktion und erreicht auch eine Selbstbeschreibung. Wenn eine API gut gestaltet ist, können Benutzer ihre Arbeit schnell und intuitiv erledigen, ohne ständig die Dokumentation durchsuchen oder Support- oder Antwort-Websites besuchen zu müssen. Sie können Bibliotheksentwicklern auch Zeit sparen, indem Sie einige Funktionen kapseln, deren Entwicklung sie selbst viel Zeit in Anspruch nehmen würde. Gutes Design spart Entwicklern nicht nur Zeit, es lässt sie auch intelligenter und verantwortungsbewusster aussehen. Wenn Sie Ihren Benutzern dabei helfen, klug und kompetent auszusehen, werden Sie noch besser aussehen!
Für Javascript ist das API-Design besonders wichtig
Unabhängig von der Programmiersprache oder dem Framework ist das API-Design für JavaScript wichtiger als für viele andere Sprachen. Erstens verfügt JavaScript als dynamische und spät gebundene Sprache über keinen Compiler, der ein Sicherheitsnetz oder eine Erkennungseinheitsfunktion implementieren kann, sodass JavaScript keine Fehler in Ihrem Code finden kann. Linting oder Validierungsframeworks wie JSLint und JSHint können uns helfen. Die Funktionen dieser Frameworks können auf einige häufige Fehler in Javascript hinweisen, sie können jedoch keine Javascript-Fehler finden, wenn wir APIs verwenden.
Alles hängt von Ihnen ab. Sie können eine gut gestaltete API entwickeln, die Ihren Benutzern hilft, in die sprichwörtliche „Erfolgsgrube“ zu fallen, was bedeutet, dass Ihre Bibliothek für Entwickler komfortabel und vertraut ist, während sie gleichzeitig eine positive Verstärkung bietet und Vertrauen aufbaut Entwickler interagieren mit Ihrem Code.
Das beste Beispiel dafür, „in die Grube des Erfolgs zu geraten“, ist die Verwendung von jQuery zum Abrufen von DOM-Elementen über die CSS-Selektorsyntax. Wenn ich beispielsweise alle Artikelelemente mit einem Klassennamen erhalten möchte, kann ich dies mit jQuery tun:
$("article.blogPost").fadeIn();
Der Selektor „article.blogPost“ verwendet genau die gleiche Syntax wie unten gezeigt. Das ist kein Zufall!
article.blogPost { border-radius: 10px; background-color: salmon; box-shadow: 0px 0px 10px 2px #ccc; }
jQuery的选择器引擎被设计为了使我和其他开发者能够使我对CSS选择器的理解和它的引擎进行交互。结果可想而知,如果jQuery需要我用一种新的,为特定目的形成的语法,我将失去快速,明显和高效。
我们可以获得灵感从这些框架中,如jQuery,或者其他框架,并应用这些灵感到我们的设计中。然而,获得灵感并不是抄袭,有个度的问题,任何设计过API的人如果是仅仅的基于别人的想法,不管好与坏,他都将继承。如果我们将在好的javascript中获得的准则运用到其他领域中,我们能开发拥有好的API的框架,这些API设计能被运用在任何情况下。
出色的Javascript APIs设计秘诀
虽然软件不具有与绘画或建筑类似的视觉评价标准,我们仍倾向于使用与物理实体一样的形容词来描述软件质量。例如,使用“优雅的”与“漂亮的”来赞美软件并不罕见。如果用与物理实体相似的形容词描述软件接口是合理的话,那么当然也可以使用与之相同的原则来评价软件设计。
在本节,将四个来自艺术领域的流行设计原则扩展至API设计中:
对每一个原则,将列出一到多个实例来说明,这些例子表明流行的Javascript库API设计是怎样遵循这些原则的。
原则1:一致性&协调性
在艺术作品中,一致性是一个作品背后不可缺少的观念,或者说设计者如何把一些事物组成连贯的一个整体。协调性,从另一方面来说,是一个作品相似元素的布局,这会在考虑整体时产生一种简洁的感觉。
对于API的设计者,这些原则可以通过在类库使用类似的和(或者)统一的元素来实现。就拿Kendo UI来说吧,一个创建富web应用程序的javascript框架。Kendo UI提供了一系列的UI控件和工具,这些都可以通过一个简单的语法初始化。比如,如果我想从一个无序列表创建一个树形控件(TreeView),我只需调用以下方法:
$("ul.tree").kendoTreeView({ /* Configuration goes here */ });
Kendo UI树形组件
如果我想通过一个列表创建一个面板PanelBar,我只需稍微改成不同的调用方法.
$("ul.panel").kendoPanelBar({ /* Configuration goes here */ });
Kendo UI 面板组件
Kendo UI 对所有组件使用一致的kendoX语法,促进整体的协调。更重要的,这样的设计依赖jQuery对象为DOM元素封装了统一的一层,使设计有利于所有熟悉jQuery开发者。数百万开发者使用类似的“土语”(jQuery语法),Kendo UI可以顺利地跨库使用。
另一个协调的案例是Backbone的[object].extend语法创建对象,继承和扩展Backbone的Models,Views,Collections和Routers的功能。用如下代码就可以创建一个Backbone Model,带有Backbone的完整支持,也可以自定义我需要的功能:
var Book = Backbone.Model.extend({ initialize: function() { ... }, author: function() { ... }, pubDate: function() { ... }, });
统一和协调的目的是让API新手感觉熟悉和舒服。通过虽然功能不同,但是语法相同或相似,使API变得熟悉,大大减轻了开发者使用新工具的负担。
原则 2 :平衡
下一条原则是平衡,组织元素时不会让某个部分过于重量级而盖过其它部分,使用时不稳定。艺术作品里,平衡就是视觉权重。即使不对称,作品中仍能感觉到不对称下的平衡,因为它遵循某种模式。上下文中的API设计的平衡,我特指代码的视觉权重和可预测性(看得出功能)。
平衡的API让人觉得其组成部分属于彼此,他们行为相同,或互补地完成一个目标。通过扩展,APIs也可以感觉平衡,它们允许开发人员简单的预测其他API并使用。如Modernizr的属性测试,它们的平衡性在两个方面,a)属性名对应HTML5和CSS术语和API名称,b)每个属性测试统一地返回true或false值。
// 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
访问一个单一的属性来告诉开发者需要了解到的相关属性,以便通过它访问每一个其他属性,一个高质量API的强大之处就在于它的简单。平衡性也保证了我写和Modernizr交互的代码在每次读写时具有相同的视觉加权。如何在我使用和访问API时看起来和感觉上一样,而不顾我的惯例。另一方面,如果Modernizr添加了一个polyfill Canvas的API,不仅仅是类库的视觉加权受到新API的影响,Modernizr的范围和用途也将大大扩大,并且我在和API交互时可预测性也受到了限制。
达到平衡的另一种方式是通过依靠开发人员对概念的熟悉获得可预测性的结果。一个典型的例子就是jQuery's selector syntax(jquery选择器的语法),它映射css1-3的选择器到自己的DOM选择器引擎:
$("#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
通过使用一个熟悉的概念并且映射到自己的类库,jquery避免了新的选择器语法,同事也创建了一个机制让新用户通过一个可预测的API快速的把类库应用到生产.。
原则 3: 相称性
接下来的原则是相称性,它是用来衡量一个作品中元素的大小和数量的。与其说一个好的API是一个小的api,相称性是相对于用途的大小。一个相称的API它的API表面和它的能力范围相匹配。
例如,Moment.js,一个流行的日期转换和格式化类库,可以把它视为具有相称性,因为它的API表层是紧凑的,它和类库的目的明确的匹配。Moment.js用于处理日期,它的API提供了便利的功能用来处理javascript Date对象:
moment().format('dddd'); moment().startOf('hour').fromNow();
对于一个有针对性的类库,像Moment.js,保持API的专注和简单是非常重要的。对于更大和更广阔的类库,API的大小应当能够反映出类库自身的能力。
拿Underscore来说,作为一个多种用途功效的库,它提供大量便利的函数,这些被设计的函数是用来帮助开发者处理javascript集合,数组,函数和对象。它的API量远远超过像Moment.js这样的库,但是Underscore也是成比例的,因为库中每个函数都有自己的功效目的。考虑下面的例子,前两个例子用Underscore来处理数组,最后一个来处理字符串。
_.each(["Todd", "Burke", "Derick"], function(name){ alert(name); }); _.map([1, 2, 3], function(num){ return num * 3; }); _.isNumber("ten"); // False
当一个库逐渐成长的过程中,维持比例的挑战变的更加具有严峻。为了确保添加进库的每个功能和函数都能加强库的目的,需要更多的考虑投入。对于一个大的库像kendo UI,易扩展性的目的并不是意味着我们需要往库中添加每个特性。对于一个像kendo一样大的库,功能对象和特性应该证明它们的价值才能被库包含。例如, Kendo UI's JavaScript 基于DataSource, 它能够被用来查询和处理远程数据。
var dataSource = new kendo.data.DataSource({ transport: { read: { url: "http://search.twitter.com/search.json", dataType: "jsonp", data: { q: "API Design" } } }, schema: { data: "results" } });
初看第一眼,它好像一个习以为常的数据源,感觉超出了库本身的基本目的。然而今天网站的装饰都需要动态数据的支持。数据源的引入允许Kendo UI可以使用一个稳定,并舒适的范式在整个库范围内来解决远程数据。
让一个API转变为一个名符其实的javascript垃圾抽屉,对于一个库的扩展这是危险的,但对于库来说,这也不是唯一的危险。掉入一个不让你的API伴随着库的成长圈套,或者由于某些人为原因,限制你库的大小,这些同样都是危险的!
不处理API增长最好的一个例子是jQuery的 jQuery or $ function。和我一样有成千上万的开发者喜欢jQurey, 但它的门户方法是有点乱的,从DOM选择到在jQuery对象中包含DOM元素,这个方法提供了超过11个独立超负荷选择方式。
就大部分而言,有些不是十分相关的特性被硬塞进同一个API。从全局看,jQuery是一个大的库并且能被认为库比例是合理的。另一方面,当我们尝试将一个功能硬塞进一个单一接口并且不考虑库比例,jQuery方法也可以实现这样的功能。
如果你发现你正在将一个不相干的特性强塞进已经存在的方法,或者正在想法设法使一个并不适合API的函数的添加合理化,你需要做的改变是松开皮带并且让库呼吸。你的用户在调用一个新的可以自我描述名字的函数时,将会更加节省时间,并且不会给另一个已经存在的方法添加负担。
原则 4: 强调性
在艺术作品中,强调是利用对比来使作品中某一方面脱颖而出形成一个焦点。在许多API中,焦点可能是一个通道或者类库主要方法的锚点。另外一个关于强调性的例子可以参考“链接”方式或者fluent API,它通过增加强调性效果突出了类库中心对象。jquery倾向于从许多功能演示中的强调这个对象:
$('ul.first').find('.overdue') .css('background-color','red') .end() .find('.due-soon') .css('background-color', 'yellow');
对于许多现代的类库,另一个关于强调的例子是可扩展性:类库创建者没有提供的那部分,会为你提供一个工具你可以自己完成相关扩展。
一个典型的例子可以参考jQuery'sfn(pronounced “effin”) namespace, 一般的扩展点可以通过数不清的插件和补充的类库来完成:
(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);
另一个扩展性的例子是Backbone的“extend”的函数,我们已经在本文中看到过:
var DocumentRow = Backbone.View.extend({ tagName: "li", className: "row", events: { "click .icon": "open", "click .button.edit": "openEditDialog" }, render: function() { ... } });
Erweiterbarkeit ist ein wichtiger Aspekt, denn sie macht uns bewusst, dass die vorhandene Klassenbibliothek nicht bedeutet, dass alles perfekt ist, und ermutigt uns auch, die Klassenbibliothek zu erweitern, die zu uns passt. Wenn Klassenbibliotheken Erweiterungen unterstützen, eröffnen sie nicht nur neue Einsatzmöglichkeiten, sondern ermöglichen auch unzähligen Entwicklern, von allgemeinen Einsatzmöglichkeiten zu profitieren. Eines der besten Beispiele ist das Framework Backbone.Marionette, eine Klassenbibliothek, die Backbone erweitert und deren Ziel es ist, „die Struktur großer JavaScript-Anwendungen zu vereinfachen“. Ohne Bibliothekserweiterungen wie Backbone wären Bibliotheken wie Marionette sehr komplex oder sogar unmöglich zu implementieren.
API-Design: nicht nur für Bibliothekscode-Autoren
Wenn Sie kein JavaScript-Bibliotheksautor, sondern ein JavaScript-Anwendungsentwickler oder -Bibliotheksimplementierer sind, haben Sie möglicherweise das Gefühl, dass die Prinzipien in diesem Artikel nicht auf Sie zutreffen. Wenn wir „API“ hören, denken die meisten von uns schließlich an Bibliotheken von Drittanbietern, genau wie das Beispiel, das ich in diesem Artikel verwendet habe
Tatsache ist, dass eine API, wie es in ihrer Definition heißt, nichts anderes als eine Schnittstelle ist, die isolierte Funktionen bereitstellt, die andere nutzen können. Lassen Sie mich nun ein altes Sprichwort verwenden, um einen wichtigen Punkt hervorzuheben: Schreiben Sie aus praktischen Gründen modularen JS-Code. Die Häufigkeit seiner Verwendung spielt keine Rolle.
Wie die in diesem Artikel genannten Bibliotheken können Sie Ihren JavaScript-Code anderen zugänglich machen. Selbst wenn die Benutzer Ihres Codes eine kleine Gruppe oder ein internes Team sind – selbst wenn Sie eine eigene private Bibliothek erstellen – müssen Sie in diesem Artikel nicht über die API-Designprinzipien und die Implementierung dieser Prinzipien nachdenken So wie es der Autor einer öffentlichen Bibliothek tut. Der Vorteil der Nutzung des API-Designs besteht darin, dass Sie, selbst wenn es nur für einen Benutzer gedacht ist, dennoch so entwerfen müssen, als ob es für Millionen von Benutzern wäre.
Da API-Design die Benutzererfahrung für Entwickler darstellt, ist es genauso wichtig wie UI-Design für Endbenutzer. So wie wir eine gute Benutzeroberfläche entwickeln können, indem wir einige Prinzipien lernen und uns auf einige gute und schlechte Beispiele beziehen, können wir auf die gleiche Weise auch ein besseres API-Design erlernen. Die Anwendung der vier in diesem Artikel erwähnten Prinzipien sowie anderer, die Sie selbst entdecken, kann Ihnen dabei helfen, hervorragende APIs zu erstellen und Benutzern ein gutes Erlebnis zu bieten.