-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.html
535 lines (480 loc) · 31.7 KB
/
index.html
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
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>This Code suuuuuuuucks</title>
<meta name="description" content="A look at a view tricky JS interview questions">
<meta name="author" content="Russell Anderson">
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent" />
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, minimal-ui">
<link rel="icon" type="image/png" href="images/RJA-Badge.png">
<link rel="stylesheet" href="css/reveal.css">
<link rel="stylesheet" href="css/theme/black.css" id="theme">
<!-- Code syntax highlighting -->
<link rel="stylesheet" href="lib/css/zenburn.css">
<!-- Printing and PDF exports -->
<script>
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.type = 'text/css';
link.href = window.location.search.match( /print-pdf/gi ) ? 'css/print/pdf.css' : 'css/print/paper.css';
document.getElementsByTagName( 'head' )[0].appendChild( link );
</script>
<style>
/* custom stuff */
div.custom_column {
float: left;
width: 50%;
padding: 0 3%;
box-sizing: border-box;
}
div.custom_column.forty {
width: 40%;
}
div.custom_column.sixty {
width: 60%;
}
.custom_column img {
display: block;
max-width: 100%;
box-sizing: border-box;
}
.reveal img.custom_transparent {
background: none;
border: 0;
box-shadow: none;
}
.clearfix:after {
visibility: hidden;
display: block;
font-size: 0;
content: " ";
clear: both;
height: 0;
}
div.bio_box {
clear: both;
float: right;
width: 50%;
padding: 0 20px;
}
.bio_box img {
border-radius: 50%;
}
.bio_box .custom_column {
padding-top: 30px;
width: 66%;
}
.bio_box .custom_column:first-child {
width: 33%;
padding-top: 0;
}
.bio_box h4, .bio_box p {
text-align: left;
font-size: 0.6em;
margin: 5px 0;
}
ul.startups {
background: rgba(255,255,255,0.6);
padding: 40px;
text-align: center;
}
.startups li {
list-style: none;
display: inline-block;
width: 49%;
margin-left: -4px;
padding: 10px 40px;
box-sizing: border-box;
}
.startups li:first-child {
width: 75%;
margin-left: 0;
}
.startups li img {
vertical-align: middle;
}
div.tweet_wrapper {
margin-top: 80px;
}
.twitter-tweet {
margin-left: auto;
margin-right: auto;
}
.reveal .monospace {
font-family: monospace;
}
.article_link img, .article_link small {
vertical-align: middle;
}
.avatar {
border-radius: 50%;
width: 100px;
}
</style>
<!--[if lt IE 9]>
<script src="lib/js/html5shiv.js"></script>
<![endif]-->
</head>
<body>
<div class="reveal">
<!-- Any section element inside of this container is displayed as a slide -->
<div class="slides">
<section class="clearfix" data-background="images/unsplash-code.jpg">
<h1 class="monospace" style="text-align: right">thisCodeSucks</h1>
<div class="custom_column"> </div>
<div class="custom_column">
<h3 style="text-align: right;">and other tales of developer hubris...</h3>
</div>
<div class="bio_box">
<div class="custom_column">
<img src="images/gravatar.jpeg" alt="me looking like a douche">
</div>
<div class="custom_column">
<h4>A talk by <a href="http://russelljanderson.com">Russell Anderson</a></h4>
<p><a href="http://twitter.com/RealRealRuss">@RealRealRuss</a></p>
</div>
</div>
<aside class="notes">
Don't linger here just get started.
</aside>
</section>
<!-- Example of nested vertical slides -->
<section>
<section data-background="images/rosettastone.jpg" >
<h2 >Some back story</h2>
<ul>
<li >Front End Developer</li>
<li >full time ~5 years</li>
<li >self-taught / colleague-taught</li>
<li >no computer science background</li>
<li >mostly client side via API</li>
<li >django, jinja</li>
</ul>
<aside class="notes">
Hey I'm Russ. I am going to give you a little back story because it definitely informs this talk. I'm a self-taught front end developer, and I've been doing it for a little over 5 years. I have worked on a number of different technology stacks, because in that relatively short period of time...
</aside>
</section>
<section>
<ul class=" startups">
<li><img class="custom_transparent" src="images/simply-agree.png"></li>
<li><img class="custom_transparent" src="images/tandumlogo.png"></li>
<li><img class="custom_transparent" src="images/lockup-horizontal-white.png"></li>
<li><img class="custom_transparent" src="images/moontoast.png" alt="Moontoast logo"></li>
<li><img class="custom_transparent" src="images/funditlogo.png" alt="Help fund it logo"></li>
</ul>
<aside class="notes">
I've worked for 5 different startups. Five. And what have all these companies had in common, besides being cash flow negative?
</aside>
</section>
<section>
<p><img src="images/maxresdefault.jpg"></p>
<h2>Build the plane while flying</h2>
<aside class="notes">
They all seem to take this strategy of "let's build the plane while flying". Meaning, we have to do things in a hurry, often with little to no idea what we actually want to accomplish product-wise. Things change constantly. And in these type of situations, under these conditions, there is a tendency to pile up Technical Debt.
</aside>
</section>
<section data-background="images/payydaye2f.jpg">
<h2><br><br><br><br><br>Technical Debt</h2>
<aside class="notes">
What I mean is... Over time, if things were patched, shortcuts were taken, or we implemented something in an inelegant way to get it out the door, we're going to have to go back and clean it up at some point. A metaphor coined by Ward Cunningham.
</aside>
</section>
</section>
<section>
<section>
<h2>Improving as a dev</h2>
<div class="tweet_wrapper">
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr"><a href="https://twitter.com/toddmotto">@toddmotto</a> if you're not ashamed of your code when you revisit it, you're not a good developer. <a href="https://twitter.com/hashtag/truestorybro?src=hash">#truestorybro</a></p>— Txus Ordorika (@txusinho) <a href="https://twitter.com/txusinho/status/786178797674594304">October 12, 2016</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
<aside class="notes">
Additionally, as I work I tend to get better, hopefully, which means I don't look back too fondly on the stuff I've previously written.
</aside>
</section>
<section>
<h2>Turning into a monster</h2>
<p style="text-align: center;">
<img src="images/dinosaur2.jpg" style="width: 40%">
</p>
<p>Borderline obsessive about how I do things</p>
<aside class="notes">
Moreso though, I've noticed that as I've gotten better I am prone to some bad habits as a result of my good habits. Mainly, I am becoming more set in my ways and obsessive about code looking and feeling a certain way. I have brought my perfectionism into it. Which means that anytime I look at old code, whether it was from a developer before me, or my own from a while ago, I think
</aside>
</section>
<section>
<h2>This code suuuuuuuuuuuuuuuuuuuuuucks.</h2>
<iframe src="//giphy.com/embed/3o7TKzUfqABuaYPo2Y" width="480" height="261" frameBorder="0" class="giphy-embed" allowFullScreen></iframe>
<aside class="notes">it sucks! So what do I do with it?</aside>
</section>
<section>
<h2>REFACTORING</h2>
<p>I rewrite the whole damn thing.</p>
<iframe src="//giphy.com/embed/fQZX2aoRC1Tqw" width="480" height="270" frameBorder="0" class="giphy-embed" allowFullScreen></iframe>
<aside class="notes">
refactor is just a fancy word for rewrite.
When do I do this? Sometimes I get it scoped. More often than not I try and rush my tasks and squeeze it in when I can. and can you guess what happens?
</aside>
</section>
<section>
<h2>Regressions, of course</h2>
<iframe src="//giphy.com/embed/tdoUaMmgtgSqc" width="480" height="404" frameBorder="0" class="giphy-embed" allowFullScreen></iframe>
<p>When code that worked, doesn't anymore. Because of something I did. Probably.</p>
<aside class="notes">If you're not familiar with regressions, it means it breaks. And of course, I have to fix it. But, regressions are the worst.</aside>
</section>
<section data-background="images/black-hole.jpeg">
<h2>Regressions are the worst</h2>
<ul>
<li>Unplanned for</li>
<li>Difficult to spot</li>
<li>Erode confidence in the whole team</li>
</ul>
<aside class="notes">Why are they the worst? Because they are completely unplanned for. You might expect there to be bugs on an implementation of a new feature, but you don't build in time to fix regressions. They can also be very difficult to spot, and may only appear under a very specific set of circumstances that are tough to test for. They can really erode confidence in a dev team. Something about a regression makes management wonder what the hell we're all doing. A lot of times I stress or miss deadlines.</aside>
</section>
</section>
<section data-background="images/redrocks.jpg">
<h2>Who is this talk for? <span class="fragment">Me.</span></h2>
<p> <br><br><br></p>
<h3 class="fragment" style="text-align: left">What do I need to tell myself?</h3>
<ul class="fragment">
<li>A few maxims worth repeating</li>
<li>How I decide if I should refactor</li>
<li>How do I refactor the right way to avoid regressions?</li>
</ul>
<aside class="notes">
Uh, me, mainly. I kind of want to emphasize that this things I've learned trying to cowboy refactoring. But hopefully it can serve as a cautionary tale. I won't presume you are as unreasonable and conniving as I can be. But here is what I need to know.
</aside>
</section>
<section>
<section data-background="images/mr-robot-s2-1.0.jpg">
<h2 style="text-align: left;" class="monospace"><br><br>Just because I didn't write it, doesn't mean it sucks.</h2>
<aside class="notes">
(Imagine these being said to you calmly by Eliot from Mr Robot)
Try and try hard to understand the code written by colleagues and former devs. There may be zero comments. It may have crazy inception like levels of cyclomatic complexity. But try. Try and try hard to work whatever I need to into the existing codebase, using existing functions. They may have made vastly different choices than I would have, but try.
</aside>
</section>
<section data-background="images/mr-robot.jpg">
<h2 style="text-align: right;" class="monospace"><br><br><br>That line of code is probably there for a reason.</h2>
<aside class="notes">
Here is a pretend dialogue. "I can't figure out what this line does. It doesn't seem to do anything. I don't even think we support that anymore. It was just left in there by mistake." Guess how that turns out? If I believe a line of code to be obsolete, proceed with extreme caution. Give that line of code the benefit of the doubt. (side note, be nice to your future self and ALWAYS remove code as soon as its obsolete)
</aside>
</section>
<section data-background="images/mrrobot.jpg">
<h2 style="text-align: left;" class="monospace"><br><br><br><br><br>There is a difference between technical debt and code that just irks me.</h2>
<aside class="notes">
Yeah. This is kinda a biggie. Yes, there are things that I want to do. I've learned a lot and all those old patterns make my stomach queasy. But that doesn't make it technical debt. Tech debt is when I've made intentionally brittle/hacky choices in order to meet a deadline, and I know it can't scale and can't be allowed to stay like it is for long. Tech debt is a risk to my software and my team.
</aside>
</section>
<section data-background="images/mrrobot1.jpg">
<h2 style="text-align: left" class="monospace"><br><br><br>What does it matter if <br>my code is perfect <br>but my software sucks?</h2>
<aside class="notes">And here it is. This is what I'm ultimately here for. To build great software. I should not lose focus on the goal. A perfect code base is not priority #1. It may be priority 2, but my focus should remain the end result.</aside>
</section>
</section>
<section>
<section data-background="images/jeopardy.jpg">
<h2><br>Game time.<br><br><br></h2>
<h3 class="fragment">Should I refactor?</h3>
<aside class="notes">Okay so now I am going to try and put those maxims to work on some real life scenarios.</aside>
</section>
<section>
<h3>Scenario:</h3>
<h4>Swapping if / elif / else in favor of dictionary lookup.</h4>
<div class="clearfix">
<div class="">
<pre><code data-trim>
if team == 'Falcons':
odds = '100 to 1'
elif team == 'Patriots':
odds = '3 to 1'
elif team == 'Titans':
odds = 'maybe next year'
</code></pre>
</div>
<div class="">
<pre><code data-trim>
super_bowl_odds = {
'Falcons': '100 to 1',
'Patriots': '3 to 1',
'Titans': 'maybe next year'
}
odds = super_bowl_odds.get(team, 'Unknown team')
</code></pre>
</div>
</div>
<p class="article_link">
<small><a href="http://stackoverflow.com/questions/11445226/better-optimization-technique-using-if-else-or-dictionary">Stack Overflow: "Better optimization technique using if/else or dictionary"</a></small>
</p>
<h2 class="fragment bottom_right">NO</h2>
<aside class="notes">
There are a few reasons why you would might to do this. Todd Motto has a good article on it. But what would my answer be? No. This is a good example of adopting a new, arguably better pattern. However, the old pattern worked just fine, if less extensible. Dropping everything to change every switch in the code base would take up too much effort. Maybe I could refactor as I go along. Comment all areas that need it changed.
</aside>
</section>
<section>
<h3 class="top_left">Scenario:</h3>
<h4>Many of my dependencies are well out of date, some are unsupported altogether.</h4>
<p>
<pre><code data-trim>
# requirements.txt
requests==0.2.0
</code></pre>
</p>
<h2 class="fragment bottom_right">YES</h2>
<aside class="notes">
This is a really good but unfortunate example of technical debt. With most dependencies, you are choosing to rely on someone else's code in order to quickly achieve a goal. The pain of keeping them up to date is the payback. Relying on old or unsupported dependencies can really hamstring future development, so yes I think it's worth the effort to try and keep these up to date, or better yet, refactor out completely ones you don't need anymore.
</aside>
</section>
<section>
<h3>Scenario:</h3>
<h4>I've created a generic utility function to replace code that's been copied and pasted in several places</h4>
<pre><code data-trim>
def plus_one_week(dt):
"""
Returns the given date plus 7 days.
"""
return dt + timedelta(days=7)
</code></pre>
<pre><code data-trim>
from ..utility.date import plus_one_week
# ...further down the page
c = self.create(user_id=user.id,
type='invitation',
redirect_url=app.config['JOIN_LINK'],
expires_on=plus_one_week(datetime.now()))
</code></pre>
<h2 class="fragment">NO, but...</h2>
<aside class="notes">Carefully assess the risk. I would say no in favor of adding comments to places where the copy/pasted code is and saying it should be replaced with the utility function. These kind of refactors are really frequent, often not in the scope of a sprint, and difficult to measure how long it will really take. I say build the function and then work it in.</aside>
</section>
<section>
<h3>Scenario:</h3>
<div class="clearfix">
<div class="custom_column sixty">
<h4 style="text-align: left">A column in the database changes name. Change template context?</h4>
</div>
<div class="custom_column forty">
<p><img src="images/coke.jpg" /></p>
</div>
</div>
<div class="">
<pre><code data-trim>
class BeveragesView(TemplateView):
template_name = 'drinks.html'
def get_context_data(self, **kwargs):
context = super(BeveragesView, self).get_context_data(**kwargs)
# leave the templates the same or change?
context['drinks'] = get_beverages(self.request)
return context
</code></pre>
</div>
<h2 class="fragment bottom_right">YES</h2>
<aside class="notes">So, this can definitely happen from time to time. I love when we introduce breaking changes for each other. However, it doesn't have to cause a lot of work for us. We can continue to use the same terminology in the front end and just assign the new name to it. What should I do? I say refactor, although it is certainly not without real risk of regression. But by leaving it inconsistent when it comes to something like your data model, you are relying on tribal knowledge to remember what means what, unless you really want to explain the difference in documentation somewhere. Yes this has happened to me.</aside>
</section>
<section data-background="images/unsplash-desktop.jpg">
<h3><br><br><br>Scenario:</h3>
<h4>A view design changes dramatically</h4>
<h2 class="fragment">YES, but...</h2>
<aside class="notes">Finally! I say. This view's code is garbage. Since we're going to redesign the whole view anyway, I'm just going to scrap it and start all over. But wait! I get finished and I realize that the designer forgot about a whole bunch of functionality in the old view, and I've got to rewrite all of that too! I was not counting on that. We'll definitley be pushing this to next sprint. -- So, a lot of times this is the temptation but I would encourage you to seek first to redo the view without a complete rewrite. Your old view probably contains a lot of tribal knowledge in it that even product people and designers have forgotten. Be wary! Resist the temptation to start from scratch.</aside>
</section>
<section>
<h3>Scenario:</h3>
<div class="custom_column sixty">
<h4><br>A function written by ex-employee is extremely complex and convoluted, but works without bugs</h4>
<h2 class="fragment">NO</h2>
</div>
<div class="custom_column forty">
<p><img src="images/complexity.png"></p>
</div>
<aside class="notes">I say skip it until I absolutely have to deal with it. It may be too complex, inception level complex, but if it is not breaking I should put my focus elsewhere. There may be other nuances in the code base I'm unaware of that will come to light later. Perhaps this dev understood some things I don't currently. Give the benefit of the doubt and move on.</aside>
</section>
</section>
<section>
<section data-background="images/PeelOffStickers.jpg">
<h2>Refactor the right way<br><br><br><br><br><br></h2>
<aside class="notes">So, let's say that I don't take any of my previous advice and I decide to refactor it all anyway. This seems likely. Is there a way that I can do it properly to minimize regressions and a future need for refactoring?</aside>
</section>
<section>
<h2>Tests</h2>
<ul>
<li>If they're not there, write them</li>
<li>Forces you to understand the code deeply</li>
<li>Strong business justification for refactoring</li>
<li>Doubles as de facto documentation</li>
</ul>
<p class="article_link">
<img src="https://pbs.twimg.com/profile_images/464310668984725504/ym-M-SNv_400x400.jpeg" alt="head shot of Eric Elliott" class="avatar" />
<small><a href="https://medium.com/javascript-scene/what-every-unit-test-needs-f6cd34d9836d#.g38doe8p2">Eric Elliott: "5 Questions Every Unit Test Must Answer"</a></small>
</p>
<aside class="notes">
For the sake of argument let's say no tests exist. If I am going to bite off a refactor, then now is the time to write them. Maybe not for the whole thing, but at least for the part I'm refactoring. And I say take a stab at writing tests for the existing code and see if I can get it to pass simply. This will force me to have a better understanding of that legacy code. It also presents a great argument to justify dedicating time to a refactor. Finally, tests can double as de facto docs for a particular view or service. Really like this article that points out that approach.
</aside>
</section>
<section data-background="images/books.jpeg">
<h2>Documentation</h2>
<h3>Write it all down</h3>
<aside class="notes">So, let's say tests are impractical, such as a major architectural rewrite. At that point at the very least I need to document as much as I possibly can. I think I have an unreasonable expectation sometimes that I'll be able to keep all the edge cases in my head. Or that by comparing what I'm creating to an older version maybe on production, that I'll be able to recreate it all. It's a fools errand. I need to try and get it all down. This can also add some business justification, though not as strong as testing. Maybe you have some of this already, but make sure it's exhaustive.</aside>
</section>
<section data-background="images/tools.jpg">
<h2>Be careful with refactor tools</h2>
<ul>
<li><a href="http://www.gnu.org/software/grep/manual/grep.html">grep</a> - find via command line</li>
<li><a href="https://www.gnu.org/software/sed/manual/sed.html">sed</a> - find and replace via command line and regex</li>
<li><a href="https://www.jetbrains.com/help/pycharm/2016.3/finding-and-replacing-text-in-project.html">PyCharm</a> or other IDEs</li>
</ul>
<aside class="notes">So originally when researching this I was going to dive into some of these tools, but now I don't think I can recommend using any of them other than grep to identify where you may need to refactor. I think using them kind of violates some of my principals.</aside>
</section>
<section>
<div class="custom_column">
<div class="tweet_wrapper">
<blockquote class="twitter-tweet" data-lang="en"><p lang="en" dir="ltr">While I'm not sure arranging your Kanban board by "stages of grief" is good for morale, I still love this: <a href="https://t.co/NUeSkiyabH">https://t.co/NUeSkiyabH</a> <a href="https://t.co/32lmsRg8ie">pic.twitter.com/32lmsRg8ie</a></p>— Richard Seroter (@rseroter) <a href="https://twitter.com/rseroter/status/788028797144535040">October 17, 2016</a></blockquote>
<script async src="//platform.twitter.com/widgets.js" charset="utf-8"></script>
</div>
</div>
<div class="custom_column">
<h2><br>Dedicate time to do it</h2>
<h3>(be transparent about it)</h3>
<p class="fragment">Easing your annoyance can be good for the business</p>
</div>
<aside class="notes">Alluded to this, but I think this is crucial. Honestly, this is one of the most difficult things is getting mgmt to take tech debt seriously, and a big part of why I often will try and do it on the sly. But by adding tests at the same time, we create a strong business justification. However, if we can't make a solid business argument for it, it might fall into the category of personal annoyance.</aside>
</section>
</section>
<section>
<h2>Slides</h2>
<p><a href="http://russelljanderson.com/refactor-slides">http://russelljanderson.com/refactor-slides</a></p>
<div class="bio_box">
<div class="custom_column">
<img src="images/gravatar.jpeg" alt="me looking like a douche">
</div>
<div class="custom_column">
<h4>Russell Anderson</h4>
<h4>Front End Developer, SimplyAgree</h4>
<p><a href="http://twitter.com/RealRealRuss">@RealRealRuss</a></p>
</div>
</div>
<aside class="notes">just started at a new job, guess what I'm doing?</aside>
</section>
</div>
</div>
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.js"></script>
<script>
// Full list of configuration options available at:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
transition: 'slide', // none/fade/slide/convex/concave/zoom
// Optional reveal.js plugins
dependencies: [
{ src: 'lib/js/classList.js', condition: function() { return !document.body.classList; } },
{ src: 'plugin/markdown/marked.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/markdown/markdown.js', condition: function() { return !!document.querySelector( '[data-markdown]' ); } },
{ src: 'plugin/highlight/highlight.js', async: true, condition: function() { return !!document.querySelector( 'pre code' ); }, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/zoom-js/zoom.js', async: true },
{ src: 'plugin/notes/notes.js', async: true }
]
});
</script>
</body>
</html>