Skip to content

Removes duplicated logic in server module#443

Closed
se7entyse7en wants to merge 4 commits intomasterfrom
remove-dup-code
Closed

Removes duplicated logic in server module#443
se7entyse7en wants to merge 4 commits intomasterfrom
remove-dup-code

Conversation

@se7entyse7en
Copy link
Copy Markdown
Contributor

@se7entyse7en se7entyse7en commented Jan 2, 2019

This depends on #442. Please see here.

@dpordomingo
Copy link
Copy Markdown
Contributor

Drone is failing because a transient failure.
You can rerun it restarting the job.
To do so, you just need to login, and then click RESTART
image

If you're not allowed to restart a job, I think you should ask @src-d/infrastructure creating an issue into infrastructure repo


type sleepyErrAnalyzer struct{}

func (a *sleepyErrAnalyzer) NotifyReviewEvent(ctx context.Context, e *lookout.ReviewEvent) (*lookout.EventResponse, error) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line is 124 characters (lll)

If you have feedback about this comment, please, tell us.

suite.sendEvent(successJSON)

suite.GrepTrue(suite.r, `msg="analysis failed" analyzer=Dummy app=lookoutd error="rpc error: code = Unknown desc = review error"`)
suite.GrepTrue(suite.r, `msg="analysis failed: code: Unknown - message: review error" analyzer=Dummy app=lookoutd error="rpc error: code = Unknown desc = review error"`)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line is 170 characters (lll)

If you have feedback about this comment, please, tell us.

suite.Run(t, &ErrorAnalyzerIntegrationSuite{
configFile: dummyConfigFile,
analyzer: &errAnalyzer{},
errMessage: `msg="analysis failed: code: Unknown - message: review error" analyzer=Dummy app=lookoutd error="rpc error: code = Unknown desc = review error"`,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line is 159 characters (lll)

If you have feedback about this comment, please, tell us.

suite.Run(t, &ErrorAnalyzerIntegrationSuite{
configFile: dummyConfigFileWithTimeouts,
analyzer: &sleepyErrAnalyzer{},
errMessage: `msg="analysis failed: timeout exceeded, try increasing analyzerReviewTimeout" analyzer=Dummy app=lookoutd error="rpc error: code = DeadlineExceeded desc = context deadline exceeded"`,
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line is 198 characters (lll)

If you have feedback about this comment, please, tell us.

getAnalyzerNotifier := func(ctx context.Context, settings map[string]interface{}) (analyzerNotifier, error) {
st := grpchelper.ToPBStruct(settings)
switch ev := e.(type) {
case *lookout.ReviewEvent:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate of server/server.go:172-179 (dupl)

If you have feedback about this comment, please, tell us.

func(ctx context.Context, a lookout.AnalyzerClient) (*pb.EventResponse, error) {
return a.NotifyReviewEvent(ctx, ev)
}, s.analyzerReviewTimeout}, nil
case *lookout.PushEvent:
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

duplicate of server/server.go:164-171 (dupl)

If you have feedback about this comment, please, tell us.

}

func (s *Server) concurrentRequest(ctx context.Context, conf map[string]lookout.AnalyzerConfig, send reqSent) ([]lookout.AnalyzerComments, error) {
func (s *Server) concurrentRequest(ctx context.Context, conf map[string]lookout.AnalyzerConfig, send reqSent, logErrorMessages map[codes.Code]string) ([]lookout.AnalyzerComments, error) {
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

line is 187 characters (lll)

If you have feedback about this comment, please, tell us.

Copy link
Copy Markdown
Contributor

@dpordomingo dpordomingo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for caring!
I think it's a good idea caring about removing duplicate code, but there are some suggestions that I'd like to do.

There is also a personal concern about changing the behavior of Server.HandleReview(Context, *ReviewEvent, bool) error when processing unsuported Events.

I also wonder if the initial implementation was coded that way (with that dupe code) considering any planned change, that might cause that both event handlers were totally different.

ev.Configuration = *st
}
return analyzerNotifier{
func(ctx context.Context, a lookout.AnalyzerClient) (*pb.EventResponse, error) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We try to avoid structs initialized with positional arguments because they're harder to read and can cause problems in some cases (like changing the order of properties having the same type, or adding new properties).

imho I'd prefer:

return analyzerNotifier{
  notify: func...
  timeot: s.analyzerReviewTimeout
}, nil

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree

return a.NotifyPushEvent(ctx, ev)
}, s.analyzerPushTimeout}, nil
default:
ctxlog.Get(ctx).Debugf("ignoring unsupported event: %s", ev)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're moving the logic to validate the event too deep

s.HandleEvent(ctx, strangeEvent) ->
    s.AnalyzeAndComment(ctx, strangeEvent, isSafePosting) ->
        s.analyze(ctx, strangeEvent, isSafePosting) ->
            s.getSender(strangeEvent) ->
                getAnalyzerNotifier(ctx, errorMsgMap) ->
                    if unsupported return fmt.Errorf("unsupported")

instead of how we did initially:

s.HandleEvent(ctx, strangeEvent) ->
    if unsupported fmt.Debug("unsupported")

I do not see the benefit of moving that validation so deep.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's another point against the refactor. The reason for this was to avoid checking twice the type of the event using the switch.

}, s.analyzerPushTimeout}, nil
default:
ctxlog.Get(ctx).Debugf("ignoring unsupported event: %s", ev)
return analyzerNotifier{}, fmt.Errorf("unsupported event: %s", ev)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I might be mistaken, but this PR is also changing the s.HandleEvent(ctx, strangeEvent) behavior when it is sent an event that was not a ReviewEvent nor a PushEvent;
If I'm rightm the s.HandleEvent(ctx, strangeEvent) will fail with an unsupported error message, instead of just logging a debug unsupported message.

If that's true, I think we should not change the behavior in a refactor PR or without a clear reasons to do so.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. With these changes the HandleEvent method fails in case on supported event. Another thing to note with this refactor is that in case of unsupported event the check is so deep that it even spawns a goroutine for each analyzer. And this is a big no-no in my opionion.

}

func (s *Server) analyze(ctx context.Context, e lookout.Event, safePosting bool) ([]lookout.AnalyzerComments, error) {
ctxlog.Get(ctx).Infof("processing event type %d", e.Type())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see more cryptic the new error message: event type 2 instead of pull request

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree on this too, in fact an idea could be to add a stringer to EventType in lookout-sdk.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In other place we are doing reflect.TypeOf(e).String()

}

func (s *Server) analyze(ctx context.Context, e lookout.Event, safePosting bool) ([]lookout.AnalyzerComments, error) {
ctxlog.Get(ctx).Infof("processing event type %d", e.Type())
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we're also missing info about the event provider (see 1326678#diff-91bbeda7eb98a7adc57b9e47e2cf5c2bL188)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right, I forgot to add it in to the log ctx.

if err == nil {
if err := s.post(ctx, e, comments, safePosting); err != nil {
s.status(ctx, e, lookout.ErrorAnalysisStatus)
err = fmt.Errorf("posting analysis failed: %s", err)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This assignment does not apply over first err definition #line-124, but over its own scope #line-126

We avoid it, doing early returns; it means, that we stop processing as soon as an error condition is met; example:

if err := doSomething(); err != nil {
    return fmt.Errorf("new deep error") // we stop processing
}
// do other things

instead of moving errors and reusing variables containing it, like in your example:

var err error
if err := doSomething(); err != nil { // we shadow the upper err definition
    err = fmt.Errorf("new deep error") // this definition does not apply over the upper scope
}
return err // nothing was overriden; we got <nil>

You can see an example about it at: https://play.golang.org/p/I75A6xUtJgN

s.status(ctx, e, lookout.SuccessAnalysisStatus)
}
}
return err
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we always introduce a new line after every code block

var comments []lookout.AnalyzerComments
if err := e.Validate(); err != nil {
return err
return comments, err
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we use to avoid indirections when doing an early return caused by an error; example:

func doSomething() (string, error) {
    var msg string
    // do things, operate with msg...
    // at  some point, we check an error, and we do:
    if err := checkSomething(); err != nil {
        return "", err // instead of `return msg, err`; relying on a previous value of `msg`
    }
}

That way, we do explicit the things that we return

conf, err := s.getConfig(ctx, e)
if err != nil {
return err
return comments, err
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem.

var comments []*lookout.Comment
analyzerNotifier, err := getAnalyzerNotifier(ctx, settings)
if err != nil {
return comments, err
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

idem. about returning errors.

@dpordomingo
Copy link
Copy Markdown
Contributor

I saw some messages from lookout-staging bot.
Some of them may be addressed, and others might not. In any case, we should proceed as they were posted by a real user:

  • addressing them if possible,
  • explaining why they can not be addressed, or
  • marking them as resolved if they make no sense and no explanation is needed.

@dpordomingo dpordomingo added the enhancement New feature or request label Jan 2, 2019
@se7entyse7en
Copy link
Copy Markdown
Contributor Author

I also wonder if the initial implementation was coded that way (with that dupe code) considering any planned change, that might cause that both event handlers were totally different.

Exactly, I was thinking the same thing that I could have been missing the big picture and future planned change.

@se7entyse7en
Copy link
Copy Markdown
Contributor Author

Overall it seems that the are some possible performance issues by eye. And even if it removes some dup code, it may trade-off the linearity of the steps too much.

Signed-off-by: Lou Marvin Caraig <loumarvincaraig@gmail.com>
Signed-off-by: Lou Marvin Caraig <loumarvincaraig@gmail.com>
Signed-off-by: Lou Marvin Caraig <loumarvincaraig@gmail.com>
Signed-off-by: Lou Marvin Caraig <loumarvincaraig@gmail.com>
suite.sendEvent(successJSON)
suite.GrepAll(suite.r, []string{
`processing pull request`,
`processing event type 2`,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hm. The previous message was much better.

@smacker
Copy link
Copy Markdown
Contributor

smacker commented Jan 4, 2019

Usually, it's a good idea to remove duplicated code, but I see 2 problems with this PR:

  1. Before there was a much more clear separation of handling different events. Despite the fact that right now we handle them in a very similar manner it can be not true anymore in the future. (for example when we start processing push event instead of just ignoring it) I believe this refactoring would make such potential changes very difficult. Same applies to new types of events.
  2. As it was already mentioned the check is too deep (it runs go-routines for unsupported events!)

Though I agree a current code of this module needs some improvements.

@se7entyse7en
Copy link
Copy Markdown
Contributor Author

I'm gonna close this PR ;)

@dpordomingo dpordomingo deleted the remove-dup-code branch January 9, 2019 10:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants