-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathbower-unlimited-bower.html
More file actions
265 lines (253 loc) · 14.7 KB
/
bower-unlimited-bower.html
File metadata and controls
265 lines (253 loc) · 14.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
<!DOCTYPE html>
<html>
<head>
<link rel="canonical" href="https://hardmath123.github.io/bower-unlimited-bower.html"/>
<link rel="stylesheet" type="text/css" href="/static/base.css"/>
<title>Bower! Unlimited Bower! - Comfortably Numbered</title>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
<meta charset="utf-8"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no" />
<link rel="alternate" type="application/rss+xml" title="Comfortably Numbered" href="/feed.xml" />
<!--
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS-MML_HTMLorMML"></script>
<script>
MathJax.Hub.Config({
tex2jax: {inlineMath: [['$','$']]}
});
</script>
-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.css" integrity="sha384-Um5gpz1odJg5Z4HAmzPtgZKdTBHZdw8S29IecapCSB31ligYPhHQZMIlWLYQGVoc" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/katex.min.js" integrity="sha384-YNHdsYkH6gMx9y3mRkmcJ2mFUjTd0qNQQvY9VYZgQd7DcN7env35GzlmFaZ23JGp" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.13.11/dist/contrib/auto-render.min.js" integrity="sha384-vZTG03m+2yp6N6BNi5iM4rW4oIwk5DfcNdFfxkk9ZWpDriOkXX8voJBFrAO7MpVl" crossorigin="anonymous"></script>
<script>
document.addEventListener("DOMContentLoaded", function() {
renderMathInElement(document.body, {
// customised options
// • auto-render specific keys, e.g.:
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false},
{left: '\\begin{align}', right: '\\end{align}', display: true},
{left: '\\(', right: '\\)', display: false},
{left: '\\[', right: '\\]', display: true}
],
// • rendering keys, e.g.:
throwOnError : false
});
});
</script>
</head>
<body>
<header id="header">
<script src="static/main.js"></script>
<div>
<a href="/"><span class="left-word">Comfortably</span> <span class="right-word">Numbered</span></a>
</div>
</header>
<article id="postcontent" class="centered">
<section>
<h1>Bower! Unlimited Bower!</h1>
<center><em><p>How not to write a module.</p>
</em></center>
<h4>Sunday, February 1, 2015 · 6 min read</h4>
<p>Bower. RequireJS. JamJS. Browserify. JQuery, Underscore, Lodash, and did I
mention JQuery? Angular, D3, Polymer, Flux, Ember.js, Backbone, React, Dojo,
Mootools, Bootstrap, Foundation, Meteor, Socket.io, Aurelia, Express.</p>
<p>What do all of these have in common?</p>
<p>For one, the fact that even though I’ve been using JavaScript for several
years, having written thousands of lines of code used by hundreds of people, I
have never used any of them. I don’t know any of their APIs. To date, every
website I’ve written was hand-coded, starting from blank HTML file. And a lot
of people frown upon that.</p>
<p>“Computers are all about automation,” you say, “There’s no good reason to
impose the drudgery of boilerplate upon yourself. You’ll end up writing lots of
duplicate code.”</p>
<p>Which is partly true. What you fail to mention is that I’d be writing plenty of
duplicate code <em>anyway</em>.
<a href="https://github.com/mbostock/d3/wiki/Requests#d3_xhr">Consider,</a>
<a href="http://api.jquery.com/jquery.ajax/">for</a>
<a href="http://mootools.net/core/docs/1.5.1/Request/Request">instance,</a>
<a href="https://github.com/Raynos/xhr">the</a>
<a href="http://dojotoolkit.org/reference-guide/1.10/dojo/xhr.html">XMLHttpRequest</a>
<a href="http://www.w3.org/TR/XMLHttpRequest/">API</a>. Each reimplementation of XHR is
basically the same thing, with slightly different method names or argument
conventions. As a developer, I would rather know the Real API—I can use it
anywhere I want, and I have unrestricted access to the entire API (so I’m not
at the mercy of someone who doesn’t think PUT requests are worth implementing).</p>
<p>Each new “web technology” has its own Wiki, API doc and “getting started” page
which you need to somehow absorb ideas from. They have their own strange
installation rituals, their own vocabulary, their own “best practices”, and
their own encyclopedia of StackOverflow answers that you must read if you have
any hope of getting stuff done.</p>
<p>Worse, though: they try to influence how you design.</p>
<p>All these “platforms” advertise themselves as “frameworks”. They force you to
structure a project so that it conforms with the architecture that they want.
They’re monoliths, and they don’t like cooperating with other monoliths.</p>
<p>That’s a horrible way to do web design. If <a href="http://eev.ee/blog/2012/04/09/php-a-fractal-of-bad-design/">PHP
hammers</a> have a
claw on each end, then JS hammers are actually disguised combined harvesters
that accept callbacks.</p>
<p>The first part of the problem is pedagogical in nature. To someone who is just
beginning to learn web development, being introduced to a monstrous framework
can lead to all sorts of misconceptions. jQuery is <em>not</em> a programming
language. JavaScript <em>can</em> change the color of text on its own.</p>
<p>Students begin to learn from a higher level of abstraction than is necessary.
Filling in the blanks by copy-pasting lots of boilerplate code is not computer
science. You should know why you’re using a tool. Experience should come before
abstraction.</p>
<p>The other part of the problem is more practical.</p>
<p>These architectures look shiny in contrived demo situations (name a modern-day
language that does not boast of a beautiful “hello-world” scenario), but in the
real world, their abstractions almost immediately begin leaking. You end up
writing patches to tide over important features marked “TODO” on Github. You
end up writing glue code, which is far worse than “the drudgery of
boilerplate”.</p>
<p>Which isn’t to say you shouldn’t be using—or writing—JavaScript libraries.
But you should be writing small, self-contained modules that provide a clean
interface that is optimized for communicating with other programs. You should
be using conventional vocabulary and idioms everywhere (even if those idioms
smell like the dead fish that is JavaScript semantics). <a href="http://www.catb.org/~esr/writings/cathedral-bazaar/">Don’t build a
cathedral</a> if you can get
things done with a stall at the bazaar.</p>
<p>Your programs should <a href="http://en.wikipedia.org/wiki/Unix_philosophy">do one thing, and do it
well</a>. It could be a small thing
or a big thing. It could be a color picker widget or a library to encode PDF
files. It doesn’t matter. It should be self-contained and present itself as a
tool. Programmers should control code; code shouldn’t control programmers.</p>
<hr>
<p>How?</p>
<p><strong>Avoid side effects.</strong> The vast majority of your functions should take inputs
and return an output. Things that change state should be limited as much as
possible, and should <em>always</em> do so because the end-user explicitly mandated
it. The moment you start messing about with global prototypes and settings, or
pushing to arrays you didn’t create, you’re going to end up taking over the
entire application.</p>
<p><strong>Namespace.</strong> Your library should expose one name. One. <code>window.something =
{}</code>. That’s it. Everything you expose should be a property of the
<code>window.something</code> object. (No, <code>window.something</code> cannot be a function, that’s
cute but annoying in practice.) <code>npm</code> enforces this, and if you’re clever, you
can write code that’s a valid <code>npm</code> module <em>and</em> browser-worthy module. Read
about
<a href="http://en.wikipedia.org/wiki/Immediately-invoked_function_expression">IIFE</a> if
you’re confused.</p>
<p><strong>Don’t force callbacks.</strong> If it doesn’t actually do anything asynchronous,
don’t add a callback. Just <em>return</em> the answer. That’s what the return keyword
is for.</p>
<p><strong>Put thought into your argument convention.</strong> If your functions are generally
monadic or dyadic, just accept positional arguments. Yes, it’s ok to write code
like:</p>
<pre><code>function (a, b) {
doSomethingWith(a || "default", b || "default");
}
</code></pre><p>and yes, it’s ok to have users call a function with <code>function(null, "cow")</code> to
default a positional argument that isn’t the last.</p>
<p>Avoid the <code>arguments</code> keyword like the plague. If you need variadicity, accept
an array as an argument. Variadicity causes confusion. And people who get
addicted end up writing functions that do different things depending on how
many arguments were passed. Scary, scary, scary.</p>
<p>It’s also perfectly ok to accept just one argument, an object, if you need a
dozen keyword arguments.</p>
<p><strong>Be quiet.</strong> When your library runs in production, nobody should notice it. No
console messages or “warnings”, no twiddling with the DOM to include a little
banner.</p>
<p><strong>Documentation is not advertisement.</strong> Once I’ve committed to using your
library, you don’t need to continue explaining how it’s a revolution in
generative fluid modern flat reactive magical material-inspired skeuomorphic
silky-smooth user interface. Just tell us how to use the primitives. If there
are concepts to be learned before using your library, explain them outside the
API reference.</p>
<p><strong>If you’re strictly on nodejs, prefer the provided Streams to whatever
homegrown thing you’re inventing right now.</strong> Streams are tempting to
reinvent-the-wheel, because they’re a pretty idea which isn’t terribly
difficult to implement with your own shiny interface. Don’t do it. This extends
to other things, too: XHR wrappers, querySelector reimplementations, and
event-emitting architectures are just a few of the major offenders.</p>
<p><strong>Document bugs.</strong> No, I won’t lose faith in your module if there’s a
one-in-a-million corner case as long as it’s documented. I will lose faith if
there’s a one-in-a-zillion corner case whose only documentation is a comment
saying “ill fix thiss l8r”. Similarly, don’t introduce undocumented features.
At the very least, say “this feature is experimental and SHOULD NOT be used in
production”.</p>
<p><strong>Don’t force dot-chaining.</strong> Yes, it’s useful in some places. Dot-chaining is
great for <em>transforming</em> values in a sequence. It makes no sense when there are
sequential actions that have side-effects. JavaScript has built-in support for
that kind of thing: it’s called the semicolon (<code>;</code>).</p>
<p>Bad:</p>
<pre><code>element
.turnRed()
.then()
.ifYouFeelLikeIt()
.and()
.theStarsAlign()
.changeSize()
.do()
</code></pre><p>Good:</p>
<pre><code>element.turnRed();
if (element.youFeelLikeIt && element.theStarsAlign) {
element.changeSize();
}
</code></pre><p>Good:</p>
<pre><code>data
.map(transformation)
.filter(selection)
.reduce(action)
</code></pre><p>The problem with dot-chaining is that it locks a lot of important functionality
behind weird objects.</p>
<p><strong>Stop creating boilerplate creators.</strong> If you’re embarking on a new
million-dollar company, you want to start from scratch and do things right,
making sure you understand everything on your website. If you’re writing a toy
demo for a 24 hour hackathon, you don’t need a full-featured MVC framework. You
need to learn CSS.</p>
<p>Corollary: throwing Bootstrap at a problem doesn’t fix it. Bootstrap causes
slow, janky websites. There was a time when it was shiny. Now it’s dull and
mundane. Put some effort into making your website look like “yours”. And
remember, there’s absolutely nothing wrong with the default OS-provided buttons
that designers at Apple have spent ages perfecting. For that matter, I feel
there’s nothing wrong with Times New Roman. It’s just that everyone feels the
need to show that they know how to change the font face.</p>
<p><strong>Don’t write generic CSS.</strong> Are you creating a set of pretty text box widgets?
Don’t touch anything that doesn’t have class <code>pretty-text-box</code>. Things that go
around setting global properties (even ones that <em>should</em> be set, like
<code>box-sizing</code>) are evil. Don’t be that guy.</p>
<p><strong>Write generic CSS.</strong> I might want to change the width of your
syntax-highlighting gutter. Don’t make me edit your source code for that to
happen.</p>
<p><strong>Don’t build plugin infrastructures.</strong> Your code should be organized enough
for people to write helpers themselves. You shouldn’t need to provide methods
to “register” an “extension”. It almost always implies you’re building a
cathedral.</p>
<hr>
<p>The TL;DR version of this is that your code should be designed to cooperate
with others. People don’t want frameworks to lock up all their hopes and dreams
in. They want small, useful tools so that they don’t have to think about too
many details.</p>
<p>UNIX wouldn’t work if it wasn’t made of hundreds of awesome tiny programs. The
Internet should take a hint from that.</p>
</section>
<div id="comment-breaker">◊ ◊ ◊</div>
</article>
<footer id="footer">
<div>
<ul>
<li><a href="https://github.com/kach">
Github</a></li>
<li><a href="feed.xml">
Subscribe (RSS feed)</a></li>
<li><a href="https://twitter.com/hardmath123">
Twitter</a></li>
<li><a href="https://creativecommons.org/licenses/by-nc/3.0/deed.en_US">
CC BY-NC 3.0</a></li>
</ul>
</div>
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-46120535-1', 'hardmath123.github.io');
ga('require', 'displayfeatures');
ga('send', 'pageview');
</script>
</footer>
</body>
</html>