The document contains notes from a talk on quality Ruby code. Some key points discussed include:
- Tests alone do not improve code quality - the code itself needs to address quality issues through approaches like linting, exception handling, and code reviews.
- Quality code is molded through a healthy code review process, uses good naming conventions, has a low "wtf" ratio, handles exceptions properly, and follows other best practices.
- When handling exceptions, it is best to rescue the most specific exceptions, retry logic as needed, raise exceptions with context, and avoid method_missing when possible. Avoiding exceptions through techniques like nil checking and block resource management is also recommended.
5. Thanks to all the bostonrb organizers!
Thank you EzCater, a good sponsor makes a huge difference!
6. Thanks to all the bostonrb organizers!
Thank you EzCater, a good sponsor makes a huge difference!
Thank you to all my friends in Indianapolis for teaching me so
much! Thank you Stacey, Aldrin, Ben, Bella, Joe, Adam,
Adrian, Orando!
7. Thanks to all the bostonrb organizers!
Thank you EzCater, a good sponsor makes a huge difference!
Thank you to all my friends in Indianapolis for teaching me so
much! Thank you Stacey, Aldrin, Ben, Bella, Joe, Adam,
Adrian, Orando!
Thank YOU for coming tonight and supporting the community!
9. My talks are intended to be interactive so
- Ask questions (wave hand, call out ‘Michael’)
10. My talks are intended to be interactive so
- Ask questions (wave hand, call out ‘Michael’)
- Hearing your opinions and experiences is very welcome
11. My talks are intended to be interactive so
- Ask questions (wave hand, call out ‘Michael’)
- Hearing your opinions and experiences is very welcome
- Prefer questions, answers, conversations during not after
12. My talks are intended to be interactive so
- Ask questions (wave hand, call out ‘Michael’)
- Hearing your opinions and experiences is very welcome
- Prefer questions, answers, conversations during not after
- Expect polls and use them to learn about your community
13. My talks are intended to be interactive so
- Ask questions (wave hand, call out ‘Michael’)
- Hearing your opinions and experiences is very welcome
- Prefer questions, answers, conversations during not after
- Expect polls and use them to learn about your community
- Cell phone and laptop use during main talk is discouraged
14. My talks are intended to be interactive so
- Ask questions (wave hand, call out ‘Michael’)
- Hearing your opinions and experiences is very welcome
- Prefer questions, answers, conversations during not after
- Expect polls and use them to learn about your community
- Cell phone and laptop use during main talk is discouraged
- Cell phone airplane mode is encouraged
15. My talks are intended to be interactive so
- Ask questions (wave hand, call out ‘Michael’)
- Hearing your opinions and experiences is very welcome
- Prefer questions, answers, conversations during not after
- Expect polls and use them to learn about your community
- Cell phone and laptop use during main talk is discouraged
- Cell phone airplane mode is encouraged
- Public Video is being recorded for most of my talks, !smile
28. 28
And… about deploying code...
- IAC Infrastructure As Code. Recipies (chef), Playbooks (Ansible), etc.
29. 29
And… about deploying code...
- IAC Infrastructure As Code. Recipies (chef), Playbooks (Ansible), etc.
- Programming configuration via a DSL (e.g. Chef count attribute)
30. 30
And… about deploying code...
- IAC Infrastructure As Code. Recipies (chef), Playbooks (Ansible), etc.
- Programming configuration via a DSL (e.g. Chef count attribute)
- Idempotent. Immutable Infrastructure. Set it. And forget it! (bow to Ronco BBQ)
31. 31
And… about deploying code...
- IAC Infrastructure As Code. Recipies (chef), Playbooks (Ansible), etc.
- Programming configuration via a DSL (e.g. Chef count attribute)
- Idempotent. Immutable Infrastructure. Set it. And forget it! (bow to Ronco BBQ)
- Set the State, let the tool manage it
32. 32
And… about deploying code...
- IAC Infrastructure As Code. Recipies (chef), Playbooks (Ansible), etc.
- Programming configuration via a DSL (e.g. Chef count attribute)
- Idempotent. Immutable Infrastructure. Set it. And forget it! (bow to Ronco BBQ)
- Set the State, let the tool manage it
- Know the key factors – docker has a daemon, ansible doesn’t and uses ssh
(port 22) to do things, etc.
33. 33
And… about deploying code...
- IAC Infrastructure As Code. Recipies (chef), Playbooks (Ansible), etc.
- Programming configuration via a DSL (e.g. Chef count attribute)
- Idempotent. Immutable Infrastructure. Set it. And forget it! (bow to Ronco BBQ)
- Set the State, let the tool manage it
- Know the key factors – docker has a daemon, ansible doesn’t and uses ssh
(port 22) to do things, etc.
- Use checklists (for developing IAS is a very good idea)
34. 34
And… about deploying code...
Why we use Terraform and not Chef, Puppet, Ansible, SaltStack, or CloudFormation
https://blog.gruntwork.io/why-we-use-terraform-and-not-chef-puppet-ansible-saltstack-or-cloudformation-
7989dad2865c
Infrastructure as Code: Chef, Ansible, Puppet, or Terraform?
https://www.ibm.com/cloud/blog/chef-ansible-puppet-terraform
Puppet vs. Chef vs. Ansible vs. SaltStack
https://www.intigua.com/blog/puppet-vs.-chef-vs.-ansible-vs.-saltstack
Comparing top DevOps tools: Docker vs Kubernetes vs Puppet vs Chef vs Ansible
https://www.znetlive.com/blog/compare-top-devops-tools-docker-kubernetes-puppet-chef-ansible/
Choosing a deployment tool - ansible vs puppet vs chef vs salt
https://gist.github.com/jaceklaskowski/bd3d06489ec004af6ed9
Puppet vs Salt vs Chef vs Ansible, which to choose?
https://www.reddit.com/r/linuxadmin/comments/9ljveg/puppet_vs_salt_vs_chef_vs_ansible_which_to_choose/
36. 36
As a Quality Engineer..
● I’m always thinking about more tests
37. 37
As a Quality Engineer..
● I’m always thinking about more tests better tests
38. 38
As a Quality Engineer..
● I’m always thinking about more tests better tests
so we can have less bugs
39. 39
As a Quality Engineer..
● I’m always thinking about more tests better tests
so we can have less bugs higher quality
40. 40
As a Quality Engineer..
● I’m always thinking about more tests better tests
so we can have less bugs higher quality
● Or we can end up solving the wrong problems !
52. 52
We need (in all code)
● Quality Code Approaches (todays topic)
● KPIs ! Not # tests/bugs, but code level
● Automated Linting, e.g. Rubocop
● Code Grading, Code Climate
● Robust exception handling (also covered today)
● Open minded Code Review mentality
● Easy to use Code Review tools
● IAC
53. 53
● Has Tests
● Is molded
● Good names
● Low wtf Ratio
● Handles Exceptions
● KISS Mr Meta gently
● Uses few parameters
● Uses Linting and Grading
● Allows a Little Duplication
Quality (Ruby) Code
● Is a choice
● Is easy to read
● Is not optimized
● Is easy to change
● Uses standards that evolve
● Uses the right rules guidelines
● Has small classes and methods
● Values comments as they are so rare
● Has less bugs
54. 54
Is Molded
Through a healthy code review process that features:
- Code is owned by all
- PR Comments are the norm
- Quality is not generally time-boxed
- Humbleness leads with pride in code not ego
- Refactoring is nearly always done in-cycle. Now
59. 59
Handles Exceptions
# Even better (scoped with re-raise)
begin
...
some code
...
rescue StandardError => e
some code
If condition still an issue can do `raise e`
end
Rescue the most specific exception possible
60. 60
Handles Exceptions
# Even Even better (scoped more with re-raise)
begin
...
some code
...
rescue StandardError::ArgumentError, ZeroDivisionError => e
some code
If condition still an issue can do `raise e`
end
Rescue the most specific exception(s) possible
61. 61
Handles Exceptions
# Sometimes (code with dependencies) you just want to retry
Example1: An API error for get prices which can be retried:
62. 62
def get_api_prices
tries = 0
begin
tries += 1
prices = api_get_buy_sell
sleep 2
rescue SocketError => e
p e.message
if (tries < 5)
p "but retrying... try: #{tries}"
sleep(2 ** tries)
retry
else
p 'giving up...'
raise e # Do not remove, we need a current price to be set
end
end
end
Handles Exceptions – Retry
Example 1
63. 63
visit_with_retry sell_url
def visit_with_retry(url, tries = 5)
begin
@s.visit(url)
sleep 2
find_link(‘login’)
rescue Capybara::ElementNotFound, Net::ReadTimeout => e
p e.message
if (tries < 1)
p "but retrying... try: #{tries}"
sleep(2 ** tries)
tries -= 1
retry
else
p 'giving up...'
raise e # Do not remove, we need a current price to be set
end
end
end
Handles Exceptions – Retry
Example 2
65. 65
raise “just the text and not the best”
Handles Exceptions – Raise them well
66. 66
raise “just the text and not the best”
raise RuntimeError, “stop executing please”
Handles Exceptions – Raise them well
67. 67
raise “just the text and not the best”
raise RuntimeError, “stop executing please”
Create custom errors (“help your fellow / future programmer):
class PaymentError < StandardError
end
raise PaymentError, “zero amount in payment field pmt-001”
Handles Exceptions – Raise them well
68. 68
raise “just the text and not the best”
raise RuntimeError, “stop executing please”
Create custom errors (“help your fellow / future programmer):
class PaymentError < StandardError
end
raise PaymentError, “zero amount in payment field pmt-001”
Pass information to exceptions
raise TemperatureError.new(180)
Then add attribute and set in initialize
Handles Exceptions – Raise them well
71. 71
- Saves the day
- Lets you code carelessly
Handles Exceptions – method missing
72. 72
- Saves the day
- Lets you code carelessly
- Makes everything feel better
Handles Exceptions – method missing
73. 73
- Saves the day
- Lets you code carelessly
- Makes everything feel better
- Is a swiss Army knife that can tear your code apart
Handles Exceptions – method missing
74. 74
- Saves the day
- Lets you code carelessly
- Makes everything feel better
- Is a swiss Army knife that can tear your code apart
- Can lead to highly opinionated programmer talking at you
Handles Exceptions – method missing
79. 79
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
80. 80
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
81. 81
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
82. 82
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
- Prefer Class Instance (self.thing) over class (@@) variables – hierarchy
83. 83
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
- Prefer Class Instance (self.thing) over class (@@) variables – hierarchy
- Always pass a parameter to reduce / inject, e.g. 0, {}, etc. due to empty issue
84. 84
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
- Prefer Class Instance (self.thing) over class (@@) variables – hierarchy
- Always pass a parameter to reduce / inject, e.g. 0, {}, etc. due to empty issue
- Manages Resources with Blocks and ensure* (db connections, file locks, etc)
85. 85
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
- Prefer Class Instance (self.thing) over class (@@) variables – hierarchy
- Always pass a parameter to reduce / inject, e.g. 0, {}, etc. due to empty issue
- Manages Resources with Blocks and ensure* (db connections, file locks, etc)
- Prefer throw-catch (last value) to raise-rescue (pass in exception)
86. 86
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
- Prefer Class Instance (self.thing) over class (@@) variables – hierarchy
- Always pass a parameter to reduce / inject, e.g. 0, {}, etc. due to empty issue
- Manages Resources with Blocks and ensure* (db connections, file locks, etc)
- Prefer throw-catch (last value) to raise-rescue (pass in exception)
- Prefer define_method to method_missing
87. 87
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
- Prefer Class Instance (self.thing) over class (@@) variables – hierarchy
- Always pass a parameter to reduce / inject, e.g. 0, {}, etc. due to empty issue
- Manages Resources with Blocks and ensure* (db connections, file locks, etc)
- Prefer throw-catch (last value) to raise-rescue (pass in exception)
- Prefer define_method to method_missing
- Simulate determinism with Mock Objects, e.g. make http fail
88. 88
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
- Prefer Class Instance (self.thing) over class (@@) variables – hierarchy
- Always pass a parameter to reduce / inject, e.g. 0, {}, etc. due to empty issue
- Manages Resources with Blocks and ensure* (db connections, file locks, etc)
- Prefer throw-catch (last value) to raise-rescue (pass in exception)
- Prefer define_method to method_missing
- Simulate determinism with Mock Objects, e.g. make http fail
- Memoize ||= expensive operations
89. 89
Handles Exceptions – avoids them
- Treat all objects as if they could be nil
- Pays attention to warnings
- Prefer Set and Struct to Array and Hash for some structured data
- unique data (Set)
- attribute names (getters, setters)
- instance and class methods
- Use module (scope) to avoid reopening classes, e.g. “class” or “initialize”
- Prefer Class Instance (self.thing) over class (@@) variables – hierarchy
- Always pass a parameter to reduce / inject, e.g. 0, {}, etc. due to empty issue
- Manages Resources with Blocks and ensure* (db connections, file locks, etc)
- Prefer throw-catch (last value) to raise-rescue (pass in exception)
- Prefer define_method to method_missing
- Simulate determinism with Mock Objects, e.g. make http fail
- Memoize ||= expensive operations - prefer local over instance
90. 90
KISS Mr Meta gently
Metaprogramming is the
answer to all programming
problems !!!
117. 117
Value comments - they are so rare
Exceptions to avoiding comments:
# Module Support to expire 12/1/2019
118. 118
Value comments - they are so rare
Exceptions to avoiding comments:
# Module Support to expire 12/1/2019
# Dependent library randomly fails here, cause unknown
119. 119
Value comments - they are so rare
Exceptions to avoiding comments:
# Module Support to expire 12/1/2019
# Dependent library randomly fails here, cause unknown
# More efficient approach here in order to save memory
123. 123
A number of voluntary activities and
approaches that Application and
Automation Engineers use to create
better quality code today
Quality Code Is
130. 130
Recursion, Linked lists (single, double,
circular), trees, binary tree searches, maps,
design patterns, etc. are all useful tools at the
right time.
However, as you’ve seen, there is a lot more
to quality than algorithms for highly
performant code </rant>