Coder Social home page Coder Social logo

hero's Introduction

Lines of Code Code Status Dependency Status Build Status Coverage Status Downloads

Sponsor

Hero

Controlling complexity is the essence of computer programming. -- Brian Kernighan

Create well organized modular apps.

I've seen my share of poor app structure. Hell, I wrote most of it. Whether is fat controllers, giant models with mystery callbacks, or a junk drawer lib directory.

The question remains. Where do I put my business logic?

Why Hero?

  • It matches the mental map of your business requirements
  • It produces testable components
  • It easily handles changing requirements
  • It reduces the ramp up time for new team members

Think of Hero as a simplified state machine.

Match the Implementation to the Business Process

The problem has always been: How do you effectively model a business process within your app?

Things start simply enough but eventually edge cases force gotchas into various libs, modules, and classes. Before you know you it, you have a lump of spaghetti that's difficult to maintain and even harder to improve.

Hero provides a simple pattern that encourages you to decompose these processes into managable chunks.


Quick Start

gem install hero

Lets model a business process for collecting the top news stories from Hacker News, Reddit, & Google and then emailing the results to someone.


Gather News

  • Get news from Hacker News
  • Get news from Reddit
  • Get news from Google
  • Email Results

Now that we have the basic requirements, lets model it with Hero.

Hero::Formula[:gather_news].add_step :hacker_news do |context, options|
  # make api call
  # parse results
  # append results to context
end

Hero::Formula[:gather_news].add_step :reddit do |context, options|
  # make api call
  # parse results
  # append results to context
end

Hero::Formula[:gather_news].add_step :google do |context, options|
  # make api call
  # parse results
  # append results to context
end

Hero::Formula[:gather_news].add_step :email do |context, options|
  # format news for email
  # compose the email
  # send the email
end

This looks surprising similar to the requirements. In fact we can publish the specification directly from Hero.

Hero::Formula[:gather_news].print

# => gather_news
#      1. hacker_news
#      2. reddit
#      3. google
#      4. email

Pretty slick. Now... lets run the process.

news = {}
Hero::Formula[:gather_news].run(news)

And we're done.

Key take aways

  • The implementation aligns perfectly with the requirements. Developers and business folks can talk the same lingo.

  • The formula is composed of smaller steps that are interchangable. We are poised for changing requirements.

  • Steps can be tested independently.

  • Each step implements the interface: def call(context, options)

Next Steps

As our app grows in complexity, we should change the steps from blocks to classes. Here's an example.

# this
Hero::Formula[:gather_news].add_step :hacker_news do |context, options|
  # make api call
  # parse results
  # append results to context
end

# changes to this
module GatherNews
  class HackerNews

    def call(context, options)
      # make api call
      # parse results
      # append results to context
    end

  end
end

Hero::Formula[:gather_news].add_step GatherNews::HackerNews.new

We should also create a directory structure that maps to the business process. Something like this.

|-app
  |-formulas
    |-gather_news
      |-hacker_news.rb
      |-reddit.rb
      |-google.rb
      |-email.rb

We also need an initializer to set the formula up.

# app/initializer.rb
Hero::Formula[:gather_news].add_step GatherNews::HackerNews.new
Hero::Formula[:gather_news].add_step GatherNews::Reddit.new
Hero::Formula[:gather_news].add_step GatherNews::Google.new
Hero::Formula[:gather_news].add_step GatherNews::Email.new

Now we have a well structured application thats ready to grow. Notice how well organized everything is.

Also note that we can write tests for each step independent of anything else. This is an important point and a powerful concept.

Deep Cuts

Logging comes for free if you register a logger with Hero. Here's an example.

Hero.logger = Logger.new(STDOUT)

Hero::Formula[:log_example].add_step :first_step do |context, options|
  context << 1
end

Hero::Formula[:log_example].add_step :second_step do |context, options|
  context << 2
end

Hero::Formula[:log_example].add_step :third_step do |context, options|
  context << 3
end

Hero::Formula[:log_example].run([])

# The log will now contain the following lines.
#
# I, [2012-08-26T11:37:22.267072 #76676]  INFO -- : HERO before log_example -> first_step Context: [] Options: {}
# I, [2012-08-26T11:37:22.267166 #76676]  INFO -- : HERO after  log_example -> first_step Context: [1] Options: {}
# I, [2012-08-26T11:37:22.267211 #76676]  INFO -- : HERO before log_example -> second_step Context: [1] Options: {}
# I, [2012-08-26T11:37:22.267248 #76676]  INFO -- : HERO after  log_example -> second_step Context: [1, 2] Options: {}
# I, [2012-08-26T11:37:22.267282 #76676]  INFO -- : HERO before log_example -> third_step Context: [1, 2] Options: {}
# I, [2012-08-26T11:37:22.267333 #76676]  INFO -- : HERO after  log_example -> third_step Context: [1, 2, 3] Options: {}

hero's People

Contributors

hopsoft avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.