code thoughts
and
other stuff
I've no idea what I'm doing
quick break down...
- being a professional
-
thinking about your code
- code design principles
- code smells
- design patterns
- tests
being a professional
Key points
- take responsibility
- know your field
- collaborate
- mentoring
- learn to say no
- managing your time
- estimations
take responsibility
- QA should find nothing
- Aim for tests to have 90%+ code coverage
- Ensure software is easily changeable (S.O.L.I.D)
know your field
- Design Patterns (Gang of Four's 24 patterns)
- Design Principles (S.O.L.I.D, DRY)
- Methodologies (Agile, Scrum, Kanban, Waterfall)
- Disciplines (TDD, BDD & a million other things)
- Artifacts (UML)
collaborate
Plan, design and write code together...
- Share knowledge between teams
- Promotes alternative solutions
- Potentially fewer errors
mentoring
- Quickly realise holes in your understanding
- Long forgotten reasons why to ignore
certain techniques - Look after juniors. Give direction
learn to say "no"
- Don't compromise quality or stability
- Don't agree to 'try'
- When saying 'no', offer compromises
- Help educate management
managing your time
The only person responsible for managing your time is you
- Only go to meetings that actually need you
- Leave a meeting if it becomes a waste of your time
- Discussions that last longer than 5mins requires data
- Avoid 'blind alleys' & 'messes' - they're a time black hole
- Keep stand-ups short and focused! (yesterday, today, blockers)
estimations
- Don't estimate a job by yourself
- Team members recognise different
problem areas
- Break tasks up into smaller sub tasks
and estimate each individual task.
Total time will likely end up greater.
thinking about your code
UML (Unified Modeling Language)
UML gives you...
- Clear and concise architecture
- Up-front design decisions
- Less errors and more efficiency
- Clarity for new team members
class diagrams
Describes Classes and their relationship to each other
--------------- ---------------
| ClassName | | ClassName |
--------------- ---------------
| Properties | --------> | Properties |
--------------- ---------------
| Methods | | Methods |
--------------- ---------------
Different arrowheads describe different relationships
(inheritance - white, composition - diamond, association - black)
(inheritance - white, composition - diamond, association - black)
object diagrams
Useful for exploring "real world" examples of
objects and the relationships between them
objects and the relationships between them
sequence diagrams
John Cleveley's MVCP (Presenter) design
failing that...
Just get your pen and paper out...
wasn't that fun!
code design principles
S.O.L.I.D
- Single Responsibility Principle
- Open/Closed Principle
- Liskov Substitution Principle
- Interface Segregation Principle
- Dependency Inversion Principle
Not always attainable, but it's worth aiming high
single responsibility
Fairly self-explanatory
-
Objects (methods too) should
have one responsibility (promotes testability)
-
Objects gain
'high cohesion' (better method relation)
Probably the single best/easiest way to improve your code!
http://csswizardry.com/2012/04/the-single-responsibility-principle-applied-to-css/
http://csswizardry.com/2012/04/the-single-responsibility-principle-applied-to-css/
open/closed
- open for extension, closed for modification
- avoid editing a base class (except to fix errors)
- but never add new functionality to a base class
- should be easy to extend a base class rules
-
utilise polymorphism (via interface contracts)
Liskov Substitution
- parent object replaceable by subtype
- promotes a more flexible system
- exposes a real IS-A relationship
- extend the base but don't modify base
LSP states: when overriding a method in a subclass:
- Signature must match parent
- what to accept must be the same or weaker
- what to expect must be the same or stronger
- Exceptions thrown must match parent
Interface Segregation
Clients should not be forced to depend on methods that they do not use.
- avoid generic interfaces
- specific interfaces increases cohesion
- avoids side-effects caused by changes
dependency inversion
- components should depend upon
abstractions instead of implementations
- relies on interfaces and polymorphism
(similar to Open/Closed principle)
- inject dependencies and
use injection containers**
**injection container
dont repeat yourself (dry)
This is a bonus slide \0/
If you're using/creating/referencing something
more than twice:
cache it
If you notice duplicated code/logic:
abstract it
CODE SMELLS
sass
-
over engineered!
- need to keep things simple
- use Sass but don't abuse it
we need a new CSS strategy! one that doesn't include a ton of...
@if $core or $tablet
...or at the very least keeps it encapsulated
CSS
- Undoing styles (reverses purpose of cascade)
- Magic numbers (they just work?)
- Qualified selectors (div.blah)
- Generic selectors (div)
- line-height units (trick question: no unit!)
- Brute forcing styles ()
- IDs
- Generic class names (.card or .credit-card ?)
javascript/jquery
- write 'plain vanilla' where possible
- follow the GUTS guidelines
- don't re-wrap jQuery objects in jQuery
- dont wrap elements in jQuery unnecessarily
- recognise other jQuery smells (see GUTS)
-
be wary of overuse...
$(this).attr('id') => this.id
remember the asset controller?
TOO much info already!
Have a read over this instead then...
- interrogate your classes (post-opt)
- transform complex data structures
- well named methods negate a need for code comments
- reduce object context (what it knows) to ensure flexibility
example patterns
- Proxy
- Strategy
- Decorator
- Factory
- Composite
- Command
a whirl wind tour...
Proxy
- place object in-between user
and requested object - many different types of proxies:
'protection' (controls access)
'remote' (cross domain data transfer)
'virtual' (performance)
strategy
Encapsulates an algorithm inside a class separating the selection from the implementation
- Mix of composition and delegation
- 'context' gets passed multiple 'strategies'
- 'context' delegates to appropriate 'strategy'
decorator
- Alter functionality of existing object
- Leaving existing object un-modified
- Different to a Facade in that the API
doesn't change (i.e. Facade creates new API)
factory
-
Provides simple interface to
create new object instances
- Allows easy change between
objects from within the Factory
(e.g. changing from object X to Y)
composite
Made up of the following pieces...The Composite Pattern describes a group of objects that can be treated in the same way as a single instance of an object may be.
- Component class (a task's base class)
- Composite class (container of sub tasks)
- Leaf class(es) (individual tasks)
command
Accumulate a number of operations
over time and execute them all at once
over time and execute them all at once
acceptance tests
"unit tests ensure you build the thing right, while acceptance tests ensure you build the right thing"
Most of my notes for 'unit tests'
applies to acceptance tests
so I'll keep this bit short...
applies to acceptance tests
so I'll keep this bit short...
things to watch out for...
- Scenarios should be concise and focused
- Avoid writing too many steps
- Step Definitions shouldn't hold application code
- Utilise Helpers to keep code maintainable
- Scenario Outlines should be 'representative'
note 'exhaustive' (you may other wise be
testing code better suited for unit tests)
unit tests
Unit Tests should be written F.I.R.S.T
(Fast, Independent, Repeatable, Self Validating, Timely)
Fast
- Should run fast
- Should be run frequently
...this should all be obvious...
independent
- Tests should not depend on other tests
- Should be able to run tests isolated
- Avoid leaky application state
repeatable
- Tests should be able to run in any environment
- This means without an internet connection
- Tests should be reliable
Otherwise you'll always have an excuse for failing tests
self-validating
- Tests should provide clear feedback
- You shouldn't have to read a log file to find out
why the test failed - This will avoid long manual evaluation
timely
- Tests should be written first (TDD)
- TDD avoids difficult to test code
- TDD avoids poorly designed code
jasmine
- Jasmine is a BDD unit-testing framework
- Much more expressive (and stable) than QUnit
- Standard features such as setUp/tearDowns
- Can write your own matchers
- No native AMD support though :-(
terminology
// Test Suite (i.e. group of related tests)
describe('Acme widget', function(){
// Spec (i.e. individual test)
it('should ...do something', function(){
// Matcher (i.e. assertion API)
expect(true).toBeTruthy();
});
});
jasmine matchers
expect(x).toBe(y);
expect(x).toBeDefined();
expect(x).toBeTruthy();
expect(x).toContain(y)
expect(x).toBeLessThan(y);
...many more...
...also can 'reverse' matchers...
expect(x).not.toBe(y);
expect(x).not.toBeDefined();
expect(x).not.toBeTruthy();
expect(x).not.toContain(y)
expect(x).not.toBeLessThan(y);
jasmine custom matchers
beforeEach(function(){
this.addMatchers({
toBeArray: function (expected) {
return Object.prototype.toString.call(this.actual) === '[object Array]' ? true : false;
}
});
this.addMatchers({
toBeNumber: function (expected) {
return /\d+/.test(this.actual);
}
});
this.addMatchers({
toBeNaN: function (expected) {
return isNaN(this.actual);
}
});
this.addMatchers({
toBeSameElementAs: function (expected) {
return expected.isEqualNode(this.actual);
}
});
});
sinon
He pretended to have deserted the Greeks and, as a Trojan captive, told the Trojans that the giant wooden horse the Greeks had left behind was intended as a gift to the gods to ensure their safe voyage home.
spies
- Track application use of methods
- Call count
- Arguments passed
- Execution order with other Spies
- Exceptions thrown
- Return values
stubs
- Pre-programmed methods
- Canned return values
- Are just 'fillers'
- Don't "directly" cause test to fail
- Actual object under test gets the
data it needs to be tested - Sinon.js Stub implementation
inherits Spy functionality
mocks
- Similar to Stubs in that they
have pre-programmed responses - Mocks have expectations of what
methods should be called on them - If expectations aren't met then test will fail
- Sinon.js Stub implementation inherits
Spy functionality
sinon.js fake timers
- Overwrites global setTimeout/setInterval
- Makes them synchronous
- Allows you to flattern timer with `tick()`
function doSomething(x){ console.log(x); }
window.setTimeout(doSomething, 1000, 'xyz');
this.clock = sinon.useFakeTimers();
this.clock.tick(1000); // trigger code that would've run after 1 sec
this.clock.restore();
SINON.JS FAKE XHR
- Overwrites global XMLHttpRequest (i.e. AJAX)
- Makes them synchronous
- Provides both fake XHR API and a high-level
fake server for multiple XHR requests
this.server = sinon.fakeServer.create();
this.server.respondWith('POST', '/success.json', [200, {}, JSON.stringify({reply: 'success', body: 'test'})]);
this.server.restore();
sinon.js adapter
Extra matchers to make Sinon.js more expressive
// instead of...
expect(spy.calledWith('foo')).toBeTruthy();
// you can use...
expect(spy).toHaveBeenCalledWith('foo');
expect(spy).toHaveBeenCalled()
expect(spy).toHaveBeenCalledWith()
expect(spy).toHaveBeenCalledOnce()
expect(spy).toHaveBeenCalledTwice()
expect(spy).toHaveReturned()
...and more...
that's it, you can go...
Code thoughts and other stuff
By Mark McDonnell
Code thoughts and other stuff
Presentation on different code design concepts and patterns as well as some best practices related to writing code and tests.
- 4,395