Software Engineering Best Practices @ Nylas

Preview:

Citation preview

Software Engineering Best Practices

Ben Gotow (@bengotow)

Computer Science ≠ Software Engineering• Clean

• Predictable

• Maintainable

• Extensible

• Fast & Efficient

• Mathematically Optimal

• Uses latest language features

Essentials• The Mafia Model

• Design Patterns

• Building a Shared Language

• Exceptions aren’t evil

• Anti-patterns

“Design software like you’re running a mafia.”

• Has one well defined job. Doesn’t ask questions.

• Has limited knowledge of the rest of the operation. Others don’t know or care how he gets the job done.

• Has no secret dealings with others, clean cut actor.

• Can be replaced—others could do this specific job if he was “removed.”

• Single Responsibility Principle (Robert C. Martin)

• Separation of Concerns (Dijkstra)

• Avoid Side Effects

• “Program to an interface, not an implementation.” (Erich Gamma)

Design Patterns

Patterns make it easy to communicate abstract ideas about software.

Design PatternsCommand EmitterSingleton

Design PatternsCommand

Encapsulate a request as an object, thereby letting users parameterize clients with different requests, queue or log

requests, and support undoable operations.

(Tasks in N1 are an implementation of the Command pattern.)

Anti-Patterns (“Code Smells”)- Copying code into more than three places

- Calling private methods on other classes

- Inspecting state which was not designed to be observed

- Waiting for something to happen using the wall clock

setTimeout I’m looking at you.😒

Anti-Patterns (“Code Smells”)Ex: Adding optional parameters that change the behavior of existing code slightly. “Don’t do this, this one time.”

thread.save({tellUser: true}) thread.save().then(() => { this.tellUser();});

Take a break, think about refactoring, explain the problem to someone else.

Naming Conventions

Naming things is hard, and really important when building software on a team.

• Functions that return a value should indicate how costly that value is to retrieve:

thread() // easygetThread() // hmm, probably not O(1)fetchThread() // better cache the result of this!

Naming Conventions

• Names should reflect intended use and give you an idea what is returned:

onClicked() // called in response to an eventnewWindow() // always returns a new objectisSending() // always returns a booleanensureReady() // may or may not do anything

• Long names are almost always worth it:finalizeAndPersistNewMessage() // shit is going down

Naming Conventions

• Functions with many parameters should use named hashes: _onComposeReply: ({thread, message, popout, behavior}) =>

• Leading (or trailing) underscores denote private members:_doInternalFileWrite myInstanceVar_

this._onComposeReply({ thread: A, behavior: reply-all, popout: true })

Naming Conventions

Exceptions aren’t EvilThrow exceptions aggressively to protect the code you write from things it wasn’t intended for.

• If your code makes assumptions, make assertions.

• If you ever have the option of crashing now, or /probably/ crashing later downstream, crash now.

Exceptions aren’t Evil

😍

Code Review

https://paper.dropbox.com/doc/Code-Reviews-using-Phabricator-LdupUMb1X9SWMyrShmhQB

Write better code, learn new tricks, avoid shipping mistakes, develop a shared understanding of the codebase.

Code ReviewCode Level:

• Clarity • Function / variable naming • Test coverage

Architectural Level:• Does this fit performance requirements? • Does this follow conventions and patterns used elsewhere? • Are we comfortable with the limitations of this approach? • Are changes well contained?

Further Reading- Design Patterns: Elements of Reusable Object-Oriented

Software (Gang of Four)

- Clean Code: A Handbook of Agile Software Craftmanship (Bob Martin)

- https://sourcemaking.com/design_patterns

- http://en.clouddesignpattern.org

ben@nylas.com

Recommended