forked from adamcath/brown-tech-talk-2013
-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathindex.html
699 lines (613 loc) · 36.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
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
<!doctype html>
<html>
<head>
<title>AppDynamics @ Brown</title>
<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">
<link rel="stylesheet" href="css/reveal.min.css">
<link rel="stylesheet" href="css/theme/default.css" id="theme">
<!-- For syntax highlighting -->
<link rel="stylesheet" href="lib/css/zenburn.css">
<!-- If the query includes 'print-pdf', use the PDF print sheet -->
<script>
document.write( '<link rel="stylesheet" href="css/print/' + ( window.location.search.match( /print-pdf/gi ) ? 'pdf' : 'paper' ) + '.css" type="text/css" media="print">' );
</script>
<!--[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>
<h1>Making sense of big applications</h1>
<h3>with AppDynamics</h3>
<p>Evan Fuller '16, Matt Cannizzaro '08</p>
<aside class="notes">
Suppose you were put in charge of operations at a major bank.
How would you manage it?
Well, a bank is not just one big program like your CS32 project.
If you manage it, you manage hundreds of different services,
running on thousands of separate machines, maybe running in another company's cloud.
How would you know if it was working or broken? Or just slow?
How would you know if your users were having a good experience?
</br>
I'm Matt Cannizzaro, this is Evan Fuller. We work at AppDynamics,
and we help people run really big and complicated applications.
</br>
We're going to spend most of this talk on technical stuff,
but I just want to give you a little more context about our company first.
</aside>
</section>
<section>
<h2>AppDynamics</h2>
<ul>
<li>Started in 2008</li>
<li>Downtown SF</li>
<li>1400+ employees (300+ engineers)</li>
<li>Acquired by Cisco in March</li>
<li>Help wanted!</li>
</ul>
<img src="images/appman.png"
style="float: right; background: none; border: none; box-shadow: none"/>
</section>
<section>
<h2>Let's build a web app</h2>
<img src="images/mono-app.png"
style="float: center; background: none; border: none; box-shadow: none;"/>
<aside class="notes">
Say you're building a web app. It might start small, but
hopefully it will need to grow. You can get bigger and bigger
boxes, until you hit the limit of what a single machine can
handle. Then what? There's really only one choice: you
need to distribute your application across multiple nodes.
</aside>
</section>
<section>
<h3>Easier said than done</h3>
<img src="images/dist-app.png"
style="float: center; background: none; border: none; box-shadow: none;"/>
<div style="margin-top:-50px"><h3>(╯°□°)╯︵ ┻━┻</h3></div>
<aside class="notes">
Writing a distributed application is not an easy task; there's
a completely new set of engineering problems that you'll
need to tackle. Soon, we'll talk about one of the most important
of these many problems: performance. But first, we'll examine a
few real-world examples of distributed applications.
</aside>
</section>
<section>
<h3>Airbnb</h3>
<img src="images/airbnb-aws.png"
style="float: center; background: none; border: none; box-shadow: none;"/>
<aside class="notes">
(https://aws.amazon.com/solutions/case-studies/airbnb/)
From this screenshot from AWS Re-Invent 2013, you can see the myriad of services
that Airbnb deploys throughout their tech stack. They deploy EC2 instances for serving content,
multiple types of storage (SQL and NoSQL), and object storage. As of 2013, they deployed over 1,000
EC2 instances for serving web content, and 50 TB worth of photos in S3.
Nathan Blecharczyk:
"pretty much any time we can use an AWS instance to solve a problem, we will, so that we don't have to solve that problem ourselves"
It is clear that over the past several years, an increasing number of companies have shifted their
perspectives to rely on collections of external web services from AWS. The increasingly complicated
topology of an application is what necessitates AppDynamics.
</aside>
</section>
<section>
<h3>MLB</h3>
<img src="images/mlb-aws.png"
style="float: center; background: none; border: none; box-shadow: none;"/>
Player Tracking System
<aside class="notes">
(https://aws.amazon.com/solutions/case-studies/major-league-baseball-mlbam/)
As one last example of an application's topology, examine MLB's Player Tracking System. This system
collects data tracking the position of the ball and players every game of the season, which in
aggregate represents 7 TB per game, or 17 PB per season. The system is implemented across so many
components in order to handle many use cases: for example, ElastiCache is used for caching large
chunks of data in memory while performing compute-heavy analysis tasks.
Keep in mind, the screenshot on this slide only shows the topology for the set of use cases I've just
gone over here. Every other project managed by MLB Advanced Media likely has similarly complex systems.
</aside>
</section>
<section>
<h3>Why performance matters</h3>
<img src="images/2017-akamai-report.png"
style="float: center; background: none; border: none; box-shadow: none;"/>
<p style="font-size: 14px; float: right;"> * courtesy of Akamai Online Retail Performance Report, 2017</p>
<aside class="notes">
There's a certain satisfaction in writing efficient, fast code.
But fundamentally, why do you need to care about performance?
Making good use of the infrastructure and resources that you
have is important, but it's not (usually) the most important thing.
Your app exists to solve your users' problems, but users are
impatient: if your app is slow, users will abandon it. This
problem is particularly bad if users have many alternatives
and the cost of switching is low. Think about booking a flight
on a travel site. If one site is slow, it's really easy to
try one of its competitors instead. If your app is a business,
bad performance costs money.
Highlights from the Akamai report included here indicate that
users expect the apps they are using to be responsive on the
resolution of a few seconds.
</aside>
</section>
<section>
<h3>How you can measure performance?</h3>
<aside class="notes">
Once you realize that you care about performance, you'll want
to understand how your app performs by measuring it. How
might you go about doing that? It would be reasonable to
start by collecting some data from each node your app is
running on, like CPU and memory utilization, how often
garbage collections are running, and things like that. This
is better than nothing, but not by much. Users don't care
about any of these things: they care about their experiences.
It's almost certainly bad if 5% of your users have a poor
experience with your app. Imagine if Google dropped one out of
every twenty searches that you ran! But could you detect
such a problem by looking at, say, CPU utilization? You'll
need a deeper understanding before you can find and fix many
types of problems.
</aside>
</section>
<section>
<h3>Your app is not static</h3>
<img src="images/ci-cd-pipeline.png"
style="float: center; background: none; border: none; box-shadow: none;"/>
<aside class="notes">
Traditionally, applications were deployed only a few times a
year, and each deployment was a major event. The rise of the
web and distributed applications has made it much easier to
deploy more often, so it's not uncommon for developers to
deploy new versions of their web apps multiple times in a
single week. This is great news for users, who benefit from
new features and bug fixes, but it introduces new problems
for performance monitoring. Since your app is constantly
changing, your performance monitor needs to be able to
quickly adapt to the new environment. A tool that requires
lengthy or complex configuration slows you down and is not
suitable for modern web application development.
</aside>
</section>
<section>
<h3>Requirements</h3>
<ol>
<li>Distributed</li>
<li>Tells the story as your users experience it</li>
<li>Require minimal manual configuration</li>
</ol>
<aside class="notes">
To recap, we need our performance monitor to be: <br/>
1. Distributed, because your app is. <br/>
2. Monitor your application performance, not the
infrastructure, because your users experience the app.
<br/>
3. Dynamically adapt to changes in your environment,
because you don't have time for configuration.
<br/><br/>
Okay, let's build it!
</aside>
</section>
<section>
<h2>Telling the story of a request</h2>
<aside class="notes">
We suspect that infrastructure monitoring is not enough, so
how will we measure performance? Your users interact with
your app over HTTP, so that's a logical place to start. If
we know when a request arrives at your server, and when your
server finishes sending the response, that's a decent
measure your app's performance from the user's perspective.
<br/>
You know when requests arrive and when the corresponding
responses are sent, so you can identify which requests are
slow, or fail outright. This helps you know when your app
is having problems, but it doesn't help you in figuring out
why. How can we do that?
<br/>
Remember that your app is distributed, so before your app
can respond to the user's request, it probably needs to make
some requests of its own to various parts of your backend,
receive and process the responses, and then generate the
response that your user sees. Let's assume that all this
communication happens over HTTP. Can we tie all these related
HTTP requests and responses together, so that you can tell
the full story of a single user request? What if we could
somehow tag related requests with some identifying
information?
</aside>
</section>
<section>
<h3>What we've got to work with</h3>
<pre><code data-trim contenteditable>
GET /dumprequest HTTP/1.1
Host: djce.org.uk
Connection: keep-alive
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_8_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/29.0.1547.76 Safari/537.36
Referer: https://www.google.com/
Accept-Language: en-US,en;q=0.8
</code></pre>
<aside class="notes">
Here's an example of an HTTP request. It has these interesting
components: <br/>
1. The HTTP method, like GET or PUT. <br/>
2. The URI, which along with the method, helps you determine
what the user is requesting. <br/>
3. The headers, which are essentially a list of key-value
pairs. <br/>
4. The request body, which is optional and could contain
arbitrary data. <br/> <br/>
If we want to add some data to an HTTP request, headers are
attractive, since we can easily add a header with some
identifying information without changing the behavior of the
rest of the application.
</aside>
</section>
<section>
<h3>Tag and follow</h3>
<img src="images/flow-map.png"
style="float: center; background: none; border: none; box-shadow: none;"/>
<aside class="notes">
When a request from a user first arrives, start by generating
a unique ID for it. At some point, the routine that is
processing the user's request may make some requests to other
nodes in your application. When this happens, add the unique
ID as a header in the request. Using this method, we can
discover every HTTP request and response that's involved in
servicing a user's request, and if the user's request is
slow, or encounters an error, we can determine where the
problem lies.<br/><br/>
Of course, out in the wild, you'll often find protocols other
than HTTP being used in the backend. The same sort of
principles apply for other protocols, but we won't get into
the details today.
</aside>
</section>
<section>
<h3>Implementation</h3>
<pre><code data-trim contenteditable>
public void send(Request req)
{
if (Profiler.isInTransaction()) {
// We are a middle node in a distributed transaction.
requestID = Profiler.getCurrentTransactionID()
} else {
// We are the root node of a distributed transaction.
requestID = Profiler.createTransactionID()
}
long startT = System.nanoTime()
req.addHeader("REQUEST_ID", requestID)
...
long endT = System.nanoTime()
Profiler.reportRequest(req, endT - startT, requestID)
}
</code></pre>
<aside class="notes">
Let's take a quick look at the implementation of the
algorithm we just described. Here's the code we'd need to
add to the routine that sends requests to tag outgoing
requests.
</aside>
</section>
<section>
<h3>Implementation</h3>
<pre><code data-trim contenteditable>
public void receive(Request req, Response res)
{
if (req.hasHeader("REQUEST_ID"))
Profiler.setCurrentTransaction(req.getHeader("REQUEST_ID"))
...
}
</code></pre>
<aside class="notes">
And here's the code we'd need to add to the routine that
handles incoming requests. <br/> <br/>
Now that we know what we want to do, how can we do it? You
could write this code in each part of your app that handles or
makes HTTP requests that passes these identifiers between
requests. It would be fairly straightforward, but tedious
and error-prone. Worst of all, it makes it hard to add new
code and nearly impossible to integrate a third party library.
So what we can do?
</aside>
</section>
<section>
<h3>How your code runs</h3>
<img src="images/code.png"
style="float: center; background: none; border: none; box-shadow: none;"/>
<aside class="notes">
For argument's sake, let's assume that your app is written
in Java. It starts out as source code, which the Java compiler
transforms into Java byte code during compilation. When it's
time to run your program, you can't just run the byte code
as is; your CPU doesn't understand byte code. So the Java
Virtual Machine does another transformation, this time turning
the byte code into native machine code. You'll recall that this
step is called just-in-time compilation, or JITing.<br/><br/>
Usually each step of this process preserves the behavior of
your code, but you certainly could imagine a transformation
that doesn't. A compiler or JIT that performed such a
transformation would be considered buggy, but if you were
careful, you could transform code in a way that
changes its behavior in a useful way while not interfering
with the purpose of the program.<br/><br/>
In theory, you could do your code transformation on either
the source code, the byte code, or the machine code. Changing
the source code would be a nightmare for the app developers,
and doing machine code transformations would require altering
the JVM and result in an implementation that's dependent
on CPU architecture, so neither is particularly interesting.
Java byte code, on the other hand, can be altered transparently,
as far as developers are concerned, and by definition, is
independent of any specific CPU architecture.
</aside>
</section>
<section>
<h3>Instrumenting an app</h3>
<pre><code data-trim contenteditable>
public void sendHttpRequest(Request request) {
...
}
</code></pre>
<aside class="notes">
Let's say that the method that implements HTTP requests in
your app looks something like this. Since few apps
re-implement this functionality from scratch, this method
is probably part of a library. In order to instrument it,
we need to transform the body of the method from this, into...
</aside>
</section>
<section>
<h3>Instrumenting an app</h3>
<pre><code data-trim contenteditable>
public void sendHttpRequest(Request request) {
Profiler.beginHttpRequest(request);
...
Profiler.endHttpRequest(request);
}
</code></pre>
<aside class="notes">
... this. We can use a technique called byte code injection
to perform this transformation at runtime. Here's how it works:
when the JVM is running a program and it needs to find the
definition of a class, it uses a special sort of object
called a class loader. The JVM provides an API to hook into
the class loading process so that your code is called after
a class loader has found the definition of a class, but
before that class's definition is available to the rest of
the program. We use this opportunity to examine
the class being loaded, and if it happens to be a class that
we are interested in instrumenting, we write new byte code
into the bodies of its methods. <br/> <br/>
Now that we are running instrumentation code at the beginning
and end of each interesting method, we can keep track of how
long each HTTP request takes, and write identifying information
into the request headers as well. This is all we need to
implement the tag and follow scheme for instrumenting HTTP.
<br/> <br/>
This technique is fundamentally straightforward, but since
our instrumentation code runs within the program being
monitored, this part of our system, called the agent, needs
to be thoughtfully engineered and tested. If the agent is
buggy, it's very possible for it to bring an application down,
which obviously defeats the whole purpose. Since the agents
monitor apps in production, they also need to keep overhead
to a minimum: we generally promise our customers no more than
2% overhead on average. AppDynamics has agents for Java,
.NET, PHP, Javascript, node.js, Android, iOS, and more.
These agents work in different ways, but the goals and
principles are similar.
</aside>
</section>
<section>
<h1>Making sense of the data</h1>
<aside class="notes">
In a production environment, there are many agents reporting
quite a large amount of data. This means that we need to have
a scalable way of collecting and aggregating all this data,
and also need to have effective visualizations to help
our users make sense of it. Let me show you our product and
demo some of the basic features.
Demo should cover: <br/>
1. Flow map <br/>
2. BTs <br/>
3. Snapshots <br/>
4. EUM <br/>
</aside>
</section>
<section>
<h1>Unsolicited advice</h1>
<p>Or, some things that you probably don't think matter, <br/>but actually really do matter.</p>
<aside class="notes">
Besides telling you about AppDynamics, Evan and I thought
it would be nice to give you something more generally useful.
We thought we could give you some unsolicited advice for your
first year after college.
You might be thinking "why the hell should I listen to this guy?
He's just some alum from years ago recruiting for some random company!"
Which is totally reasonable. I don't expect you to just take my word
on this stuff. Instead, listen to my arguments and see if you're convinced.
And I welcome discussion during this part, so please interrupt me
if you have questions.
</aside>
</section>
<section>
<h2>1) Do code reviews</h2>
<aside class="notes">
Getting your code reviewed makes you a better programmer, for the same reason that
getting your essays graded makes you a better writer. This one is pretty simple.
But there's also a huge benefit for the reviewer. Who here is or has been an
undergrad TA or head TA? Remember how much better you learned the material
when you TA'ed the class than whan you took it originally? Reviewing code is like that.
It makes you engage with the material on a deeper level. It expands your perspective
and forces you to re-examine your beliefs about what good code is.<br/>
When you interview, ask about code reviews. It's very diagnostic. A culture that does code reviews
is a culture that values quality and craftsmanship. That's the kind of place where you're really going
to learn.<br/>
</aside>
</section>
<section>
<h2>2) Learn tech that transfers</h2>
<p>Not proprietary stacks.</p>
<aside class="notes">
I used to work at Adobe, and one of the reasons I left is that I had become an expert on Flash, which is
a dead technology. When I applied to my next job, I basically had to apologize for that.
So one obvious tip is: don't waste time on dead technology.<br/>
But there's a subtler issue too, which is proprietary technology - technology that is owned and
maintained only by one group of people. All the reasons that people don't like to USE proprietary
technology apply at least twofold when it comes to LEARNING proprietary technology. Proprietary
knowledge is by definition not useful outside of a very small context.
That means it has virtually no value when you look for your second job.
I know you're all focused on your first job right now, but you should always keep in mind how your first
job is going to prepare you for your second job.<br/>
Now, you might think "isn't it more important that I learn transferable skills, ideas, and principles?"
Yes, of course that's more important. But when you only know Adobe- or Google- or Facebook-specific
libraries, you are a little bit boxed in. If you know all the industry-standards, on the other hand,
you're like a code McGuyver: when you non-technical friend comes along with some startup idea,
you can just make it happen.<br/>
I have to say that it's pretty hard to avoid proprietary knowledge at a big company.
At most big companies, you will be surrounded by layers of proprietary software in every direction.
Small companies just haven't been around long enough to accumulate that. They also don't have the
luxury to indulge in "not invented here" syndrome.<br/>
I also need to make a plug for AppDynamics specifically. Facebook has this amazing VM for running
PHP code super fast. If you work at Facebook, you can learn how that works. If you work at Google,
you can learn how about Google's insanely scalable database works. But if you work at AppDynamics,
you can learn about how TiVo works, how Nasdaq works, how Expedia works, how Okta works.
Because our job is to undestand, and help our customers understand, how these big apps really work.
It doesn't get much more generally-applicable than that!<br/>
</aside>
</section>
<section>
<h2>3) Get real feedback</h2>
<aside class="notes">
The first product I worked on at Adobe was really cool. We talked to potential customers and they
thought it was cool. We worked hard on it for 3 years and shipped it.
Then we found out there was no real market for it because it didn't <i>really</i> fit into
anyone's workflow.<br/>
The "potential customers" didn't mention that part. It's really easy to say "that's so cool, I would
totally use that!" It's a totally different thing to actually break your habits and change your
workflow.<br/>
On my product at AppDynamics, we did it right. We shipped a working version (with a limited feature set)
three months after we started the project. And people <i>actually</i>
started using it. They filed bugs! They made feature requests. And we added the things they wanted.
And we got more users. And it was glorious.<br/>
I had an interesting experience at AppDynamics that expanded my perspective again. Shortly after
we shipped my product, my team was in a meeting with the founders and the VP of engineering,
deciding what to work on next. There were two broad possibilities: features that would make the product
more useful (since it was fairly limited), and features that would allow us to charge people to
use the product. I said "I think we should focus on making the product useful before worrying about
charging for it. Once we have something we know is valuable, then we can charge for it." Jyoti, our founder
(who is also an engineer), replied "How will we know if it's valuable if nobody is paying for it?"<br/>
At first that struck me as just really really...capitalistic. But as I thought about it, I realized
he had a point: people who are using a free product will not necessarily give you the feedback you need
to make a product somebody is willing to pay for.<br/>
Now, I'm not saying this is the only way to do it. What I am saying is that if you want customer
feedback to help guide your decisions, you need to think hard about how to get the right feedback.<br/>
</aside>
</section>
<section>
<h2>4) Stay close to the business</h2>
<p>Sorry, this means money.</p>
<p>Full-stack visibility.</p>
<aside class="notes">
When I looked for my first job, I thought "I want to work on hard problems with smart people, and maybe
do something that improves the world". And most of my friends had the same criteria. It's very tempting
to not worry too much about the business. But there are some business considerations that can have a
material impact on your career.<br/>
First, a very harsh reality: if you're not working on something that generates revenue, your project
is expendable. It doesn't matter what your manager says. It doesn't matter if the CTO is coming around
your desk every week to check on the status. If it doesn't solve some real problems for some real people
who know they have these problems and are willing to pay you to solve them, it is a ship adrift on the
fickle seas of corporate strategy. Maybe the CTO gets pushed out of the company for some reason, and the
new CTO doesn't understand the value of your product. Maybe the CEO can't figure out how to justify
the cost on the quarterly earnings call. There are a thousand ways for a product to die. But if it's
solving real problems for real customers and making money...it has much better chances.<br/>
Second: it's really valuable talk to non-engineers on a regular basis.
If you don't talk to the sales team, you really don't know anything about your business.
The same goes for operations, customer support, and marketing.
This will make you better at your job. It will make you more valuable to the company.
You will learn a lot. And if you think you might want to start your own company some day,
you'll have a huge advantage because you'll know how a business really works.
Note that this is really hard to do in a big company.<br/>
Both of these are also much easier to do in small companies. Most small companies don't have the luxury
of working on non-business-critical things for any length of time. And in a small company, you'll be
surrounded by non-engineers simply because there aren't enough engineers to buffer you from them.<br/>
</aside>
</section>
<section>
<h2>5) Beware of tech debt</h2>
<p>Your code lives longer than 3 months!</p>
<aside class="notes">
Throughout college and past tech internships you may have had, you likely have never worked in the
same body of code for longer than 3 months. In the process of writing said code, you likely cut a few
corners and used a few hacky workarounds to make something work for the sake of wrapping up a project.
Once you start working full-time, however, you're going to have to live with the consequences of these
kinds of shortcuts. When you take shortcuts to save yourself a few days of work, your best case scenario
is that you have to solve the problem later on. Your worst case scenario is you establish a pattern in
your codebase that other team members will then take to heart, and then a large section of logic may
become built on a flimsy foundation. It's almost always better to do it right the first time, rather
than punting responsibilities for later.
</aside>
</section>
<section>
<h2>6) Coffee, lunch, beer</h2>
<aside class="notes">
You will spend more time with your coworkers in an average week than most of your college friends. The
value you gain from getting to know them is immense not only on a personal level, but also on a career
level. These people can help mentor you about technical issues and design patterns, but also about the
mistakes they've made in their careers, and how to navigate your own career best.
Don't be afraid to extend these sorts of meet-ups outside of your team! I have met with the CEO and
an engineering VP multiple times just to catch up on each other's lives, give mutual feedback, and
discuss careers. Getting to know lots of different perspectives throughout the corporate ladder can
only help your understanding of your company and career.
</aside>
</section>
<section>
<h3>Pro tips summary:</h3>
<ul>
<li>Go to lunch and happy hours with your coworkers</li>
<li>Beware of tech debt</li>
<li>Stay close to the business</li>
<li>Get real feedback</li>
<li>Learn tech that transfers</li>
<li>Do code reviews</li>
</ul>
</section>
<section>
<h1>Cisco</h1>
<aside class="notes">
</aside>
</section>
<section>
<img src="images/logo.png" style="padding: 20px; background: #ffffff;"/>
</section>
</div>
</div>
<script src="lib/js/head.min.js"></script>
<script src="js/reveal.min.js"></script>
<script>
// Full list of configuration options available here:
// https://github.com/hakimel/reveal.js#configuration
Reveal.initialize({
controls: true,
progress: true,
history: true,
center: true,
theme: Reveal.getQueryHash().theme, // available themes are in /css/theme
transition: Reveal.getQueryHash().transition || 'default', // default/cube/page/concave/zoom/linear/fade/none
backgroundTransition: 'slide',
// Optional libraries used to extend on reveal.js
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, callback: function() { hljs.initHighlightingOnLoad(); } },
{ src: 'plugin/zoom-js/zoom.js', async: true, condition: function() { return !!document.body.classList; } },
{ src: 'plugin/notes/notes.js', async: true, condition: function() { return !!document.body.classList; } }
]
});
</script>
</body>
</html>