Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patterns #18

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,8 @@ This holds all of our best practices.
## Project Practices

1. [Core Project Presentations](projects/core_presentation.md)

## Encouraged Design & Code Patterns

1. [Three Levels of Thinking](patterns/three_levels_of_thinking.md)
1. [Complete Constructor](patterns/complete_constructor.md)
125 changes: 125 additions & 0 deletions patterns/complete_constructor.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
# Complete Constructor

_NOTE: Some of the phrases used here come from "Smalltalk Best Practice Patterns" by Kent Beck, *Constructor Method*_

In just about every language that is Object-Oriented (or allows/encourages the use of Object-Oriented techniques), the concept of _instance creation_ is present.

## Assumption(s)

* You have created a class/prototype with an _Intention Revealing Name_
* Programmers who want to use the class will ask, "What does it take to create an instance?"
* There is an interface to instances of your class with other _Intention Revealing Names_

## Discussion

* Single responsibility principle says one method does one thing
* Some languages make constructors a single method, others separate constructors into a class-specific constructor names and instance-specific initializers

One could just use the standard way of creating new instances and then send a serious of messages to put the instance into a useable state.
There is a lot of flexibility in doing this.
However, it is not obvious what state an object needs to be in to successfully use the rest of the interface.

## Solution

Provide obvious instance creation methods that create well-formed instances.
Pass all required parameters to them, giving each of their parameters _Intention Revealing Names_.

Users should not be able to create an instance that they can not use without sending a bunch of other messages to set it up before you send it further instructions.
I.e. they should not expect an error to occur when sending a message to an object that they just constructed.
And, of course, the Complete Constructor method does nothing else besides construct the object.
It would not have side effects like modifying one of the objects that was sent in as a parameter, or automatically call another public non-setter method.

## Examples

### Ruby

The initializer should give you an object that you can then send messages to in order to make things happen.

```ruby
class Thing
def initialize(name)
@name = name
end

def doYourThing
...
end
end
```

So, without having to read the implementation details of any of the methods, one who would like to use the Thing class would write…

```ruby
thing = Thing.new(name)
thing.doYourThing
```

vs.

```ruby
thing = Thing.new
thing.name = name
thing.doYourThing
```

vs.

```ruby
thing = Thing.new(name) #which after it creates the instance of thing automatically sends :doYourThing
```

The following:

```ruby
numberArray = %w(1 2 3)
thing = AnotherThing.new(numberArray)
```

should not modify numberArray (e.g. doing a `pop`) on the numberArray inside the Constructor/Initializer

### JavaScript

There are a variety of decent articles to teach about Constructors in JavaScript, including:

* [Some Javascript constructor patterns, and when to use them](http://www.samselikoff.com/blog/some-Javascript-constructor-patterns/) - written November 14, 2013 but still a good overview
* [JavaScript Tutorial OOP Patterns](http://javascript.info/tutorial/oop)

```js
function Thing(name) {
this._name = name;
}

Thing.prototype.doYourThing = function() {
...
}
```

So, without having to read the implementation details of any of the methods, one who would like to use the Thing class would write…

```js
var thing = new Thing(name);
thing.doYourThing();
```

vs.

```js
var thing = new Thing();
thing._name = name;
thing.doYourThing();
```

vs.

```js
var thing = new Thing(); // which after it creates the instance of thing authomatically sends :doYourThing
```

The following:

```js
var numberArray = [1, 2, 3];
var thing = new AnotherThing(numberArray);
```

should not modify numberArray (e.g. `numberArray.pop()`) on the numberArray inside the Constructor/Initializer
118 changes: 118 additions & 0 deletions patterns/three_levels_of_thinking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,118 @@
# Three Levels of Thinking

_NOTE: This can be found in a different form in our RoleModel Way series of talks._

Whenever we think about our systems there are three levels of thinking:
* Conceptual
* Specification
* Implementation

Each level should be distinct and reflected in our code.

## Assumption(s)

* Code is read more often than it is written
* You understand the importance of _Intention Revealing Names_

## Discussion

All systems have a context. They cover one or more problem spaces or domains.
> "Naming classes is your biggest billboard for communicating about your system. The first thing readers will look at when they look at your code is the names of the classes. Those names will go beyond your code. Insidiously, they leak into everyday conversation...
Good class names provide insight into the purpose and design of a system. They reveal underlying metaphors. They communicate themes and variations.
They break the system into parts and show how the parts get put back together."
>
> p. 61, Classes, Smalltalk Best Practice Patterns, Kent Beck

These are the subjects of your programming literature.

All methods have a context. In a pure object-oriented system, they are always in the context of an instance of a class or the class itself.
The method signatures are the predicates of your programming literature.

Inside the methods are the implementation. They draw their context from the method signatures inside the context of a class.

This is where the sentences and paragraphs are put together. Messages are sent to objects.
If _Intention Revealing Names_ are used for classes and method signatures,
the implementation can read almost like natural language.

## Solution

In order to allow readers to grok your code at the Conceptual, Specification, and Implementation levels,
You must write your code with these three levels of thinking in mind at all times.

Classes should be named to convey their purpose and answer the question, `What is this component responsible for?`
Typically these are nouns or short noun phrases that further qualify the context in which the main noun is appropriate.

Method signatures should indicate `What command does this execute?` or `What question does this answer?` without having to read the implementation details.
Parameters should have type suggesting names.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do intent that to mean things like using format_string over format?

Copy link
Member Author

@kauerrolemodel kauerrolemodel Jul 1, 2016

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is a great question... does format imply string type?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

format implies either String or Regex types to me.


The internal code of a method should exploit the power of the conceptual class names and the specification level method signatures
with role suggesting variable names.
Instance variables (or properties) and the implementation of methods answer the question `What information does the component manage?` and
`How does it execute the commands and answer the questions specified in its interface?`

## Examples

### Ruby

The initialize method should use either named arguments or keyword arguments
so that it is clear how one initializes an instance
without having to read the implementation or knowing the names of instance variables.

```ruby
class PlayingCard
def initialize(rank, suit)
@rank, @suit = rank, suit
end
end
```

or

```ruby
class PlayingCard
def initialize(rank:, suit:)
@rank, @suit = rank, suit
end
end
```

but NOT

```ruby
class PlayingCard
def initialize(attributes)
@rank, @suit = attributes[:rank], attributes[:suit]
end
end
```

### JavaScript

Constructors should use explicitly named arguments
so that it is clear how one initializes an instance of a particular type of object
without having to read the implementation or know the names of the private properties of the object.

```js
function PlayingCard(rank, suit) {
this._rank = rank;
this._suit = suit;
}
```

but NOT implicit arguments

```js
function PlayingCard() {
this._rank = arguments[0];
this._suit = arguments[1];
}
```

and NOT arguments as a generic object/hash

```js
function PlayingCard(attributes) {
this._rank = attributes.rank;
this._suit = attributes.suit;
}
```