CODE QUALITY

ON

REFERRAL MANAGER

A.K.A

EQIPIA

HIRE MY FRIEND AND PAY ME

EMPHELUNGMANAGER

[ADD HERE WEIRD GERMAN NOUNS]

 

GOAL

Have the best code ever because that's what makes us happy.

Focus points

  • Part 1: Specs
    • Fragile
    • Not testing the real stuff
  • Part 2: SOLID
    • Rigid code
    • Coupled code
  • Part 3: Processes & Culture
    • Better code reviews
    • Surprise proposals =P

NOW COMES THE BULLSHIT PART

1. SPECS

HAVING SPECS != TESTING

class Genius
  attr_reader :number

  def initialize(number)
    @number = number
  end

  def be_a_genius
   number * super_weird_Calculation
  end

  private

  def super_weird_calculation
    ...
  end
end
RSpec.describe Genius do
  subject { described_class.new(number) }

  let(:number) { 10 }

  describe '#number' do
    it 'assigns the number' do
      expect(subject.number).to eq(number)
    end
  end

  describe '#be_a_genius' do
    it 'returns something' do
      expect(subject.be_a_genius).to be_present
    end
  end
end
RSpec.describe Genius do
  subject { described_class.new(number) }

  let(:number) { 10 }

  describe '#be_a_genius' do
    it 'returns the super calculation' do
      expect(subject.be_a_genius).to eq(1023464323)
    end
  end
end

Fragile specs

Synchronizer

Importer

Transformer

Saver

Options:

  1. Mock all the things
  2. Integration test
  3. 1 + 2

We need to decide

2. SOLID

Divide responsabilities & inject'em

Base class

  • Parse
  • Normalize
  • Send

Child class

  • super.Parse
  • custom.Normalize
  • super.Send

Parser

  • Parse

Normalizer

  • Normalize

Sender

  • Send

Class

  • Parser.call
  • Normalizer.call
  • Sender.call
class DefaultParser
  include Service

  ...
end

class DefaultNormalizer
  include Service

  ...
end

class DefaultSender
  include Service

  ...
end
class Class
  include Service

  DEFAULT_PARSER = DefaultParser
  DEFAULT_NORMALIZER = DefaultNormalizer
  DEFAULT_SENDER = DefaultSender

  def initialize(data, options = {})
    @data = data
    parser = options.fetch(:parser, DEFAULT_PARSER)
    normalizer = options.fetch(:normalizer, DEFAULT_NORMALIZER)
    sender = options.fetch(:sender, DEFAULT_SENDER)
  end

  def call
    sender.call(normalized_data)
  end

  private

  def normalized_data
    normalizer.call(parsed_data)
  end

  def parsed_data
    parser.call(@data)
  end
end

ADVANTAGES

Better specs

(we can inject both mocks and real classes)

Moar flexible

(we can modify behaviour without modifying the code)

OTHER THINGS WE COULD START APPLYING

THE ACTIVE NOTHING PATTERN

IDEAS?

THAT WAS A LOT OF BULLSHIT, RIGHT?

3. ACTUAL PROPOSALS

HOW DO WE PUSH THIS THINGS FORWARD?

CODE REVIEW

QA check specs for possible scenarios

ASK FOR IT

DO IT

Pair reviewing

Don't be afraid to propose big changes

WHEN CODING

Boy scouting

If you see something small you don't like... FIX IT!

If writing specs is hard... go fix the code to make it easier :)

Ask for help!

CRAZY IDEAS

Refer a Book!

Read some chapters of a book every 2 weeks / 1 month / whatever

Gather and discuss

Decide what to apply, document possible cases

Use those example cases when boy scouting :)

Team reading club

DO SOME KATAS!

When guiris in BCN, do at least 1 kata per week.

Pairing katas

Discuss solutions, share approaches

Decide what to apply, document possible cases

Use those example cases when boy scouting :)

HAVE BREAKFAST WHILE DOING IT! =P

NO MOAR BULLSHIT

NOW YOU CAN TALK

Code quality

By uesteibar

Code quality

  • 961