Giter Club home page Giter Club logo

Comments (8)

carlthuringer avatar carlthuringer commented on June 8, 2024

Hi, I'm pleased to find this issue here; I was just searching around for a gem that could help with an idea I had about exceptions in ruby, defensive programming, and degrading functionality while still completing the request.

I've been reading Armstrong 2003 and while getting excited about Erlang I feel frequently in my work that we don't have adequate patterns to express multi-step processes and write code that tolerates failure from other components or apps. I enjoy using light service to encapsulate steps and shrink classes, but when there's an exception, it just drops out, or if you fail_with_rollback! you can run the rollback block.

I need to think more about this to decide what sort of API to propose, but off the top of my head I'm considering either providing an array of ordered fallbacks to the reduce method, or writing the fallbacks into the action itself.

class CalculatesTax
  include LightService::Organizer

  def self.for_order(order)
    with(:order => order).reduce(
        [FetchesTaxRangesAction, FetchesCachedTaxRangesAction],
        LooksUpTaxPercentageAction,
        CalculatesOrderTaxAction,
        ProvidesFreeShippingAction
        fallback: GenericErrorHandler
      )
  end
end

I think the former is preferable, if you can provide a generic failure action as an additional parameter. That way you avoid coupling generic error handling code to specific, small actions and avoid inflating those classes. Perhaps there's a little of value in both...

from light-service.

padi avatar padi commented on June 8, 2024

For writing fallbacks into the action itself, can't you do the following (when a failure happens within an action)?:

class FetchesTaxRangesAction
  include LightService::Action
  executed do |ctx|
    begin
      // fetch tax ranges here
    rescue TaxApi::ApiLicenseInvalid => e
      // use alternative api license
    rescue => e # any other error
      // fetch cached tax ranges
    ensure
      // does something regardless if this succeeds or not
    end
  end
end

This is what first popped in my head when I read your suggestions @carlthuringer:

class FetchesTaxRangesAction
  include LightService::Action
  executed do |ctx|
    // fetch tax ranges here
  end

  fallback do |ctx|
    // fetch cached tax ranges
  end
end

Although I'm not exactly sure how it will be helpful (or if I understood the problem of this issue at all). Already in the wee hours so pardon me if this doesn't make sense.

from light-service.

carlthuringer avatar carlthuringer commented on June 8, 2024

I want to minimize the use of control structures to handle errors, and instead provide alternatives actions to the Organizer. It's important that each Action is completely unaware of the alternatives. Lower coupling, ease of modification, and improved readability, which are all key goals of light-service, as I understand it.

Sometimes it may be necessary to know exactly what the error was, and correct it specifically, as you demonstrated with the alternate api license. In those cases I think that the argument tips in favor of plain ruby begin...rescue blocks.

Given a little bit more time I hope I can come up with a more compelling case where this makes sense as an alternative to just specifying one or more fallbacks as blocks with a fallback macro. It may be that each pattern has benefits (decoupling vs context/responsibility of action).

The point behind supplying alternative actions is to avoid coding error-handling logic inside of the actions, and instead build a framework that automatically attempts something more achievable when the optimum solution fails. Each successive alternative in the array of actions should be easier to achieve than the previous, and somewhat degraded.

Full Example Gist

I admit that I don't have a complete plan/philosophy of where the responsibility for handling errors lies, but I find that the removal of the nil check is very compelling. Unfortunately my example is contrived, and many, many things could be done instead to avoid the need for a nil check, so I hope this won't distract from the proposal.

from light-service.

jpmoral avatar jpmoral commented on June 8, 2024

@carlthuringer
This is a bit late but couldn't you do something like

class CalculatesTax
  include LightService::Organizer

  def self.for_order(order)
    with(:order => order).reduce(
        [FetchesTaxRangesAction, FetchesCachedTaxRangesAction],
        LooksUpTaxPercentageAction,
        CalculatesOrderTaxAction,
        ProvidesFreeShippingAction
      )
  rescue
    GenericErrorHandler.execute
  end
end

?

from light-service.

adomokos avatar adomokos commented on June 8, 2024

We needed to signal the warning in the context, back to the controller. It means the Organizer processed, records were saved, but something happened the user should be aware of.

from light-service.

adomokos avatar adomokos commented on June 8, 2024

I think we need a larger, more concentrated effort around error handling/warning. Can I close this issue or is there anything else to discuss?

from light-service.

adomokos avatar adomokos commented on June 8, 2024

I don't see much activity around this issue. Can I close it? I don't think I have the need for it right now.

from light-service.

adomokos avatar adomokos commented on June 8, 2024

Well, I already asked this question 5 months ago, closing it now.

from light-service.

Related Issues (20)

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.