53
making your JavaScript debuggable Patrick Mueller @pmuellr, muellerware.org senior node engineer at NodeSource http://pmuellr.github.io/slides/2015/11-debuggable-javascript http://pmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdf http://pmuellr.github.io/slides/ (all of Patrick's slides) 1 / 53

making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

  • Upload
    others

  • View
    14

  • Download
    0

Embed Size (px)

Citation preview

Page 1: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

making your JavaScriptdebuggablePatrick Mueller @pmuellr, muellerware.orgsenior node engineer at NodeSource

http://pmuellr.github.io/slides/2015/11-debuggable-javascript http://pmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdf http://pmuellr.github.io/slides/ (all of Patrick's slides)

1 / 53

Page 2: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

code reading

making your JavaScript debuggable

2 / 53

Page 3: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

I'm doing 90% maintenance and 10%development, is this normal?

Stack Overflow

In 2001, more than 50% of the globalsoftware population is engaged inmodifying existing applications ratherthan writing new applications.

Capers Jones

code reading making your JavaScript debuggable

3 / 53

Page 4: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

you will write a little codeyou will read a lot of codeoptimize for readability

code reading making your JavaScript debuggable

4 / 53

Page 5: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

pyramid of doomfs.readdir(".", function(err, files){ files.forEach(function(file) { fs.stat(file, function(err, stats){ if (!stats.isFile()) return fs.readFile(file, "utf8", function(err, data){ console.log(file, data.length) }) }) })})

code reading making your JavaScript debuggable

5 / 53

Page 6: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

pyramid of doom fixed - 1fs.readdir(".", cbReadDir)function cbReadDir(err, files) { files.forEach(eachFile)}function eachFile(file) { fs.stat(file, (err, stats) => cbStatFile(err, stats, file))}function cbStatFile(err, stats, file) { if (!stats.isFile()) return fs.readFile(file, "utf8", (err, data) => cbReadFile(err, data, file))}function cbReadFile(err, data, file) { console.log(file, data.length)}

code reading making your JavaScript debuggable

6 / 53

Page 7: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

pyramid of doom fixed - 2fs.readdir(".", cbReadDir)function cbReadDir(err, files) { files.forEach(eachFile)}function eachFile(file) { fs.stat(file, cbStatFile) function cbStatFile(err, stats) { if (!stats.isFile()) return fs.readFile(file, "utf8", cbReadFile) } function cbReadFile(err, data) { console.log(file, data.length) }}

code reading making your JavaScript debuggable

7 / 53

Page 8: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

pyramid of doom - unnamedfunctions!fs.readdir(".", function(err, files){ files.forEach(function(file) { throw new Error("huh?") })})

// Error: huh?// at path/to/script.js:6:11// at Array.forEach (native)// at path/to/script.js:5:9// at FSReqWrap.oncomplete (fs.js:82:15)

code reading making your JavaScript debuggable

8 / 53

Page 9: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

pyramid of doom - unnamedfunctions fixed!fs.readdir(".", cbReadDir)function cbReadDir(err, files) { files.forEach(eachFile)}function eachFile(file) { throw new Error("huh?")}

// Error: huh?// at eachFile (path/to/script.js:9:9)// at Array.forEach (native)// at cbReadDir (path/to/script.js:6:9)// at FSReqWrap.oncomplete (fs.js:82:15)

code reading making your JavaScript debuggable

9 / 53

Page 10: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

pyramid of doom - see also

async - npm - Caolan McMahon

Promises - Axel Rauschmayer

code reading making your JavaScript debuggable

10 / 53

Page 11: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

linting and code style - standard$ node_modules/.bin/standard

standard: Use JavaScript Standard Style (https://github.com/feross/standard) path/to/bole.js:1:22: Strings must use singlequote. path/to/bole.js:3:18: Strings must use singlequote. ...

(it never ends)

No decisions to make. No .eslintrc,.jshintrc, or .jscsrc files to manage. It justworks.

code reading making your JavaScript debuggable

11 / 53

Page 12: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

other things

keep functions shorter than a "page"; v8 will"inline" short functions!

one-line arrow functions - no return orbraces needed!

[ 1, 4, 9 ].map(x => Math.sqrt(x)) // [ 1, 2, 3 ]

lots of great general ideas in Code Complete

code reading making your JavaScript debuggable

12 / 53

Page 13: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

logging

making your JavaScript debuggable

13 / 53

Page 14: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

The most effective debugging tool is stillcareful thought, coupled with judiciouslyplaced print statements.

Brian W. Kernighan

logging making your JavaScript debuggable

14 / 53

Page 15: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

console.log()

console.log(__filename + ": foo")// prints: /path/to/script.js: foo

console.log("foo", "bar")// prints: foo bar

console.log({x:1, y:2})// prints: { x: 1, y: 2 }

console.log("a-%s-b %j", 1, {x:1})// prints: a-1-b {"x":1}

console.log(process)// prints: { title: 'node', ...many lines... }

logging making your JavaScript debuggable

15 / 53

Page 16: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

console.time()

console.time("foo")doStuff()console.timeEnd("foo")

function doStuff() { // takes a long time}

// prints: foo: 1121ms

logging making your JavaScript debuggable

16 / 53

Page 17: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

console.trace()

function a() { b() }function b() { c() }function c() { console.trace("foo") }

a()

// Trace: foo// at c (<program>:3:24)// at b (<program>:2:16)// at a (<program>:1:78)// at ...

logging making your JavaScript debuggable

17 / 53

Page 18: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

console.table()???

// dream code!

const people = [

{firstName: 'George', lastName: 'Bush'},

{firstName: 'Barack', lastName: 'Obama'},

]

console.table(people)

// index firstName lastName

// ----- --------- --------

// 0 George Bush

// 1 Barack Obama

logging making your JavaScript debuggable

18 / 53

Page 19: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

logging that stays in yourcode

logging making your JavaScript debuggable

19 / 53

Page 20: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm debugconst debugA = require("debug")("thing-A")const debugB = require("debug")("thing-B")

function a() { debugA("thrashing") }function b() { debugB("churning") }

setInterval(a, 500); setInterval(b, 333)

$ DEBUG=* node debug.jsthing-B churning +0msthing-A thrashing +0msthing-B churning +339msthing-A thrashing +501ms...

logging making your JavaScript debuggable

20 / 53

Page 21: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm winstonconst winston = require("winston")

const transports = winston.transports

winston.remove(transports.Console)winston.add(transports.Console, { level: "warn" })winston.add(transports.File, { filename: "x.log" })

winston.info("info message")winston.warn("warning message")winston.error("error message")

// prints:// warn: warning message// error: error message

logging making your JavaScript debuggable

21 / 53

Page 22: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm bunyanconst bunyan = require("bunyan")

const log = bunyan.createLogger({name: "myapp"})log.level("info")

log.info("hi")

// prints// {"name":"myapp", "hostname":"my-hostname",// "pid":49675, "level":30, "msg":"hi",// "time":"2015-10-27T03:49:14.759Z", "v":0}

// du -h bunyan - 2.5M

logging making your JavaScript debuggable

22 / 53

Page 23: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm boleconst bole = require("bole")

const log = bole("myapp")bole.output({ level: "info", stream: process.stdout })

log.info("hi")

// prints// {"time":"2015-10-27T03:56:45.762Z",// "hostname":"my-hostname", "pid":53014,// "level":"info", "name":"myapp", "message":"hi"}

// du -h bole - 144K

logging making your JavaScript debuggable

23 / 53

Page 24: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm hookerfunction preCall(name) {

const args = [].slice.call(arguments,1)

log("->", name, args)

}

function postCall(result, name) {

log("<-", name, result)

}

hooker.hook(Math, Object.getOwnPropertyNames(Math), {

passName: true,

pre: preCall,

post: postCall

})

Math.max(5, 6, 7)

Math.sqrt(2)

logging making your JavaScript debuggable

24 / 53

Page 25: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm hooker

prints:

-> Math.max: [5,6,7]<- Math.max: 7-> Math.sqrt: [2]<- Math.sqrt: 1.4142135623730951

also provides

filtering argumentsoverriding results

logging making your JavaScript debuggable

25 / 53

Page 26: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

error handling

making your JavaScript debuggable

26 / 53

Page 27: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

builtin process eventsprocess.on("exit", code =>

console.log("exiting with code: " + code))

process.on("uncaughtException", err =>

console.log("uncaught exception: " + err.stack))

function a() { throw new Error("die die die") }

a()

// prints:

//

// uncaught exception: Error: die die die

// at a (.../script.js:9:22)

// at Object.<anonymous> (.../script.js:11:1)

// ... more stack trace lines

// exiting with code: 0

error handling making your JavaScript debuggable

27 / 53

Page 28: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

Error.prepareStackTrace() - before

try { a() } catch(err) { console.log(err.stack) }

function a() { b() }

function b() { c() }

function c() { throw new Error("foo blatz") }

// Error: foo blatz

// at c (.../script.js:5:22)

// at b (.../script.js:4:16)

// at a (.../script.js:3:16)

// at Object.<anonymous> (.../script.js:2:7)

// at Module._compile (module.js:456:26)

// ...

error handling making your JavaScript debuggable

28 / 53

Page 29: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

Error.prepareStackTrace() - after

Error.prepareStackTrace = function(err, stackTrace) { ...}

try { a() } catch(err) { console.log(err.stack) }function a() { b() }function b() { c() }function c() { throw new Error("foo blatz") }

// Error: foo blatz// script.js 13 - c()// script.js 12 - b()// script.js 11 - a()

error handling making your JavaScript debuggable

29 / 53

Page 30: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

Error.prepareStackTrace = ...

function v8PrepareStackTrace(error, callSites) { for (let callSite of callSites) { const funcName = callSite.getFunctionName() const file = callSite.getFileName() const line = callSite.getLineNumber() ... } return outputString}

reference: javascript_stack_trace_api.md

error handling making your JavaScript debuggable

30 / 53

Page 31: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm longjohn - before

a()

function a() { setTimeout(b, 100) }

function b() { setTimeout(c, 100) }

function c() { throw new Error("foo") }

// Error: foo

// at c [as _onTimeout] (/path/to/script.js:6:22)

// at Timer.listOnTimeout [as ontimeout] (timers.js:110:15)

error handling making your JavaScript debuggable

31 / 53

Page 32: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm longjohn - after

if (process.env.NODE_ENV !== 'production')

require('longjohn')

a()

function a() { setTimeout(b, 100) }

function b() { setTimeout(c, 100) }

function c() { throw new Error("foo") }

// Error: foo

// at [object Object].c (path/to/script.js:6:22)

// at Timer.listOnTimeout (timers.js:92:15)

// ---------------------------------------------

// at [object Object].b (path/to/script.js:5:16)

// at Timer.listOnTimeout (timers.js:92:15)

// ---------------------------------------------

// at a (path/to/script.js:4:16)

// at Object.<anonymous> (path/to/script.js:2:1)

// ...

error handling making your JavaScript debuggable

32 / 53

Page 33: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

actual debugging

making your JavaScript debuggable

33 / 53

Page 34: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

builtin module replvar repl = require("repl")

function a(i) { var context = repl.start("repl> ").context context.pi = 3.14 context.arg = i}

a(3)

// repl> pi// 3.14// repl> arg// 3// repl>

actual debugging making your JavaScript debuggable

34 / 53

Page 35: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

builtin debuggerfunction a() { debugger var x = 1 var y = 2 console.log(x + " + " + y + " = " + (x+y))}

setTimeout(a, 1000)

actual debugging making your JavaScript debuggable

35 / 53

Page 36: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

builtin debugger

> node debug debugger.js< debugger listening on port 5858connecting... ok...debug> watch("x")debug> contbreak in debugger.js:2Watchers: 0: x = undefined

1 function a() { 2 debugger 3 var x = 1 4 var y = 2debug> next

...debug> nextbreak in debugger.js:4Watchers: 0: x = 1

2 debugger 3 var x = 1 4 var y = 2 5 console.log(x + " + " ... 6 }debug> cont< 1 + 2 = 3program terminateddebug>

actual debugging making your JavaScript debuggable

36 / 53

Page 37: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

npm node-inspector

Chrome Dev Tools user interface

breakpointssteppingwatches

but for debugging node

actual debugging making your JavaScript debuggable

37 / 53

Page 38: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

IDEs with debugging support

IntelliJ IDEA

Visual Studio Code

actual debugging making your JavaScript debuggable

38 / 53

Page 39: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

cpu profiles / heap snapshots

V8 provides a built-in sampling cpu profiler

see time spent in expensive functionsshows stack for those functions

V8 provides a built-in heap snapshot facility

dumps a representation of ALL JS objects

actual debugging making your JavaScript debuggable

39 / 53

Page 40: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

cpu profiles / heap snapshots

npm v8-profiler

StrongLoop

N|Solid

These tools generate files that can be loaded inChrome Dev Tools. StrongLoop and N|Solidalso provide their own viewers.

actual debugging making your JavaScript debuggable

40 / 53

Page 41: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

cpu profiles - pro tips

NAME YOUR FUNCTIONS

always set NODE_ENV to "production"

(environment variable)

use node --no-use-inlining if yourfunctions are getting inlined

more info at Google's Chrome DevTools site

actual debugging making your JavaScript debuggable

41 / 53

Page 42: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

heap snapshots - pro tips

data is organized by class name

if classes won't work, inject "tags" (namedclass instances) into objects you want to track

take two snapshots, then "Comparison view"to see object counts diffs between the two

more info at Google's Chrome DevTools site

actual debugging making your JavaScript debuggable

42 / 53

Page 43: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

heap snapshots - tagging thingsclass RequestTag {}

class ResponseTag {}

...

function requestHandler(req, res) {

req.__hstag = new RequestTag

res.__hstag = new ResponseTag

...

}

Now you can search the snapshot for "tag" tosee all tagged objects.

actual debugging making your JavaScript debuggable

43 / 53

Page 44: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

demo - memory leak

server that leaks request objects -demos/snapshot-untagged.js

same server, but tags request and responseobjects - demos/snapshot-tagged.js

run both, take heap snapshots, and you cansee from the 'tagged' version exactly what'sleaking, since requests are instances ofIncomingMessage

actual debugging making your JavaScript debuggable

44 / 53

Page 45: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

demo - cpu profiling

program with a number of small functions -demos/profile-inline.js

run with no special flags - most of thefunctions will be inlined, and no longervisible in stack traces

run with --no-use-inlining - none of thefunctions will be inlined, and all will bevisible in stack traces

actual debugging making your JavaScript debuggable

45 / 53

Page 46: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

want to help build moredebugging tools?

making your JavaScript debuggable

46 / 53

Page 47: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

moar debugging tools!

lots of low hanging fruit

what do other languages support?what did Smalltalk and LISP do 30 yearsago?

lots of data from existing v8 debugging tools

also needed - better typesetting of code

how can you help? making your JavaScript debuggable

47 / 53

Page 48: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

Node.js Tracing Work Group

one of the many Node.js Working Groups

working on low-level, real-time tracing APIsand tools

come join us at a hangout; meeting minutesat github.com/nodejs/tracing-wg

how can you help? making your JavaScript debuggable

48 / 53

Page 49: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

cpu profiles

tree of function invocation records

for each function

functions called, available as childrennumber of "ticks" spent executing code

Highlight expensive functions/lines in your

editor?

Find which module is uses the most CPU?

how can you help? making your JavaScript debuggable

49 / 53

Page 50: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

heap snapshots

tons of data; even a small snaphot ismegabytes in size

start with npm snapshot-utils

example: displaying all "variables" in ashapshot

how can you help? making your JavaScript debuggable

50 / 53

Page 51: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

Human Factors

and Typography

for More

Readable

Programs

1990Ronald M. Baecker,Aaron Marcus

ISBN 0201107457

how can you help? making your JavaScript debuggable

51 / 53

Page 52: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

how can you help? making your JavaScript debuggable

52 / 53

Page 53: making your JavaScript debuggable - GitHub Pagespmuellr.github.io/slides/2015/11-debuggable-javascript/slides.pdfmore info at Google's Chrome DevTools site actual debugging making

fin

making your JavaScript debuggable

53 / 53