Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pascal/refactor error signatures #869

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

Pascal-Delange
Copy link
Contributor

@Pascal-Delange Pascal-Delange commented Feb 21, 2025

Goal

This PR should be entirely ISO in terms of business logic.
The starting point for me was to remove the GetBoolReturnValue and GetStringReturnValue helper methods on the NodeEvaluation type. The reason for this is that they provided no real simplification over repeated code, because they replaced "null check and type assert" logic by "catch sentinel errors everywhere" logic. Namely, the codebase was a mess of if errors.Is(err, ast. ErrNullFieldRead) {...} else if err != nil {...}.

Continuing on this path, I completely removed the following sentinel errors from the models/ast package:

  • ErrNullFieldRead
  • ErrNoRowsRead
  • ErrPayloadFieldNotFound
    Only ErrDivisionByZero remains as a specific error at runtime, because that should be the only error we really encounter.

Note that old rule dtos ast.ExecutionError can still return the NoRowsRead, PayloadFieldNotFound values and that rules can still have the NullFieldRead status (if they return a nil not a bool).

In the same logic, the models.ErrScenarioTriggerConditionAndTriggerObjectMismatch error, that was possibly returned by EvalScenario and caught higher up the stack for a side effect of "don't create a decision" or "return a 400 error", is dropped in favor of explicitly returning a boolean (for "trigger condition [not] passed")

implementation details

A nasty piece of code that recreated go error types from (integer) ExecutionError DTOs is replaced, decision rule models now hold a proper ExecutionError rather than an error that can be mapped to it.

Bug fixes

  • fixed a bug, where test run executions where the trigger condition has changed to become more restrictive would create a noisy error log when the trigger condition does not pass.

Design reflexions

In the end, what this PR attemps to fix is a design that seemed ok at the start but became a horrible mess to memorize, never mind understand.

My take away from it is: using generic sentinel errors to trigger specific side effects at some level of the caller stack is ok in the following cases:

  • the returned error is designed to be caught and handled immediately above in the call stack - kind of like io.Reader can return an EOF error that is always handled where the reader is actually read
  • the sentinel error is general enough that its use can be relatively universal throughout the codebase, e.g. how we return a 400 at the API level if errors.Is(err, models.NotFoundErr)

but the pattern where a very specific sentinel error is returned by a method down the stack to be hopefully caught several layers above and through module boundaries is a big "no".

@Pascal-Delange Pascal-Delange force-pushed the pascal/refactor-error-signatures branch from 9414730 to 88ce091 Compare February 24, 2025 15:33
@Pascal-Delange Pascal-Delange marked this pull request as ready for review February 24, 2025 16:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant