Skip to content

Instantly share code, notes, and snippets.

View paulghaddad's full-sized avatar

Paul Haddad paulghaddad

View GitHub Profile
@paulghaddad
paulghaddad / gist:a130f3807db78e5ba0c3
Last active August 29, 2015 14:08
Level Up 2: Knows the cases where comments are really necessary
So, I lied above obviously. Sometimes comments are actually necessary.
Name (and defend) some cases where you should add comments to your code.
1. Comments that are intended to be compiled into public API documentation; using
rDoc, for instance.
2. Rescue an exception that causes nothing to happen. A comment
is needed to explain why this is necessary, because it is expected
that something should happen when the exception is rescued.
Although this can be alleviated by creating a method that is called
@paulghaddad
paulghaddad / gist:fcfaaeb4305c7f21d99b
Last active August 29, 2015 14:08
Exercise: Knows why comments lie, and how to write self-documenting code
1. Take a break from the exercises for a bit. Explain why we say that 'comments lie'.
Comments often "lie" because the code they explain often changes down the road, either
through bug fixes, refactorings, or updates. The person making the changes
may either forget to update the comment, or neglect them because they aren't
a high priority. Either way, the comment doesn't adequately reflect what the code
does, and thus, "lies".
2. If we don't trust comments, how do we explain our code adequately to others?
@paulghaddad
paulghaddad / gist:4826b0b799f0a69c2e97
Last active August 29, 2015 14:08
Level Up 3: Knows why we "Don't trust the developer"
1. Developers are a tricksey bunch. Name some reasons why you shouldn't just trust the person who wrote the code.
- All developers are human and make errors.
- Their interpretation of the requirements is only one possibility; there are many others that could even be better.
- Developers are inherently optimistic, and believe their solution is correct, when in fact they may have
overlooked ambiguities in requirements, or simply not recognized these ambiguities.
- Humans have cognitive biases that cause poor decisions. These include:
-- Confirmation bias: the tendency to search for information that confirms our beliefs instead of information
that points out we are wrong.
-- Framing bias: people can come to different conclusions on the same information depending on how the information
@paulghaddad
paulghaddad / gist:6197d0ebd8a55fa569aa
Last active August 29, 2015 14:08
Level Up 3: Understands Red -> Green -> Refactor
Explain how the red / green / refactor cycle works, and how it creates better code over time.
The red / green / refactor cycle explains the process of Test-Driven Development. The Red part of the cycle denotes a failing test. This failing test is written before any code. After the test is written, it should be run. Since code hasn't yet been written, the test should fail. Then you move on to the next step in the cycle: green.
In the green step, the simplest code is written to make the test pass. Perfection is not the goal of this step; making the test pass is. Once the test passes, you can be confident the test is actually testing the code in question since it initially failed, and then passed. Then it is on to the final step: refactoring.
During this step, which is only performed when the code is green, the goal is to refactor the code to make it better. Some of the things to focus on include: ensuring there is no duplication in the system; making the code expresses your intent, clearly and concisely; a
@paulghaddad
paulghaddad / gist:a87d0682baf97805fbfc
Created November 18, 2014 19:56
Level Up 3: Uses and understands unit, functional and integration tests
1. You've now written two types of tests. Name them, and explain the differences.
The two tests I have written thus far are unit and integration tests. Unit tests validate the functionality of individual methods, they are at a low level of the code. In contrast, integration tests are at a higher level, and test a particular feature or workflow of an application, such as going to the home page, logging in, and being redirected to a particular page. The integration tests exercises a series of actions on the application and validates the desired responses. Instead of testing individual methods, integration tests validate whether a number of methods, controllers, router, models and views work in combination in successfully performing the feature or workflow.
2. Name the other type of test that you haven't written yet, and write an example of one.
Functional Tests test the various actions of a single controller, such as: Was the web request successful? Was the user redirected to the right page?
An example of a
@paulghaddad
paulghaddad / gist:c4e08684de85df946106
Last active August 29, 2015 14:10
Level Up 3: Knows why flapping tests are destructive
1. First, tell me what a flapping test is. Then, explain some ways that flapping tests are more destructive than even failing or non-existent tests.
Flapping tests are those that are non-deterministically green. They may fail, then pass the next time you run them, hence, "flapping".
Flapping tests are more destructive than failing or non-existent tests because they force us to visit many more tests each time we modify our codebase, leading to decreased productivity. For a normal failing test, we actually expect the test to fail initially, and it is just a matter of writing working code to make the test pass. Furthermore, when you experience flapping tests, you lose confidence that your test is actually doing its job: verifying a specific part of the application is working properly.
2. Name some gotchas when writing tests that can cause them to become fragile, and how to fix those problems.
- The browser environment: Never assume the page has loaded; the markup you are asserting against exists; your AJAX r
@paulghaddad
paulghaddad / gist:84aef25e0b8d9ead512b
Last active August 29, 2015 14:10
Level Up 3: Knows why manual testing doesn't scale
1. Name some cases where manual testing is preferable or necessary to verify code.
Manual testing is essential for usability testing. This should be performed with real users, under real environmental conditions. This form of testing looks at human factors: is the software easy to use?
2. Name some strategies for manually testing code that constrain the time cost of testing
To limit the amount of time spent manually testing, the tests should be performed frequently and as early as possible during each iteration. This pinpoints problems early, where they can be fixed more easily. If these tests are conducted at the end of a project, you may find problems that take a lot of time to fix, lead to many additional iterations, and thus tests--and time--in the future. Another technique to constrain the time spent on testing is to use Timeboxing, which enforces a set period of time on an activity, in this case, testing. Before starting, a time limit is agreed upon, and once reached, testing stops.
@paulghaddad
paulghaddad / gist:3508cfdbee578d28a542
Last active August 29, 2015 14:10
Level Up 3: Understands how "writing the code you want to see" makes for better code
1. Explain the theory around 'writing the code you want to see'.
At it's essence, "writing the code you want to see" means forgoing starting at the class level, whatever that may be, and working at the high level. This will produce much simpler interfaces between classes. Once you get the interfaces of the classes built, can you delve lower into each one, writing the logic, algorithms and data structures that will eventually form the classes of your application.
Writing high level integration tests, and making them pass, leads to coding in this fashion. The tests will start you at a high level, and eventually tell you to delve deeper into the implementation of the application. This leads to a minimal implementation that consists of simple, expressive interfaces.
2. Create a short gist illustrating a place where violating this rule would cause you to write worse code.
Suppose I am creating a blog application. If I don't start with integration tests, I would likely start at the model level. Because I don'
@paulghaddad
paulghaddad / gist:300c5a2992243132eb93
Last active August 29, 2015 14:10
Level Up 3: Writes meaningful tests, and knows what tautological tests are
Suppose we have a Rails model: Article
In the following tautological test, we aren't testing the the #camel_case_title method is actually doing anything:
describe Article, '#camel_case_title' do
it 'returns the title in camel case format' do
article = double(:article)
article.stub(:camel_case_title).and_return("The_Best_Article")
@paulghaddad
paulghaddad / gist:8bf44b641f390588f64e
Created December 1, 2014 21:18
Level Up 4: Understands how 'Convention Over Configuration' helps us
Explain how "convention over configuration" allows us to be more productive as a group.
We need to recognize that our needs aren't unique, and must embrace our commonalities as a group. By pushing back against the impulse to create our own solutions to previously solved problems, we allow ourselves to become more productive as a group through shared solutions and tools. A good example of this is the layer of abstractions in our web application stack: assembly-level; C; OSX; POSIX; Ruby; Rack and Rails. By using these shared solutions, we save time by only building what's necessary, and leaving it to the community to build everything else we need. There is no need to recreate the abstraction layer that is OSX to build a web application. Instead, we spend our time experimenting at the top of the stack.
Shared solutions give us standards and allows a group to progress by building even more solutions at the top of the stack. At the core, we take shared problems that the community has, and create shared solutio