zevarito / mixpanel

Simple lib to track events in Mixpanel service. It can be used in any rack based framework.
MIT License
273 stars 84 forks source link

Adding engage endpoint #46

Closed GBH closed 11 years ago

GBH commented 11 years ago

So now it's possible to manage people via /engage endpoint. I added engage_set and engage_add methods, also the generic engage one to keep things dry.

Looks like this:

  @mixpanel.engage_set(@user.id, {:username => @user.username, :email => @user.email})
  @mixpanel.engage_add(@user.id, {:monkeys_punched => 12})

I reshuffled some code inside tracker.rb. The only adjustment I needed to do is remove endpoints from @url attribute as I wanted to reuse initialized @mixpanel tracker. Otherwise you need to spin up a separate one if yo want to track events and people.

Moved special person properties parser into it's own method. It won't mutate passed in hash either. Wanted to do similar thing for event tracking, but can't find any documentation. I know $signup is a thing, can't find others.

Added all necessary tests.

Emerson commented 11 years ago

This is an exciting addition to the codebase.

dombort commented 11 years ago

+1

zevarito commented 11 years ago

Hi @GBH,

Yesterday I receive another pull request which adds engage endpoint.

https://github.com/zevarito/mixpanel/pull/45

I will take my time to analyze both before merge. Thoughts and comments are appreciated.

sturgill commented 11 years ago

There are only so many ways to skin a cat, and both approaches are similar enough. There are some stylistic differences, but I don't think one is necessarily better than the other. That said, this pull request does take into account special properties whereas I didn't.

I don't think it really matters which pull you merge: this one should work as is, and my approach can be amended to include special properties.

Coin toss as far as I can see.

GBH commented 11 years ago

I think the only major difference is that in my patch you can reuse same tracker instance:

@mixpanel = Mixpanel::Tracker.new(MIXPANEL_API_KEY, { }, :async => true)
@mixpanel.track_event('Signup')
@mixpanel.engage_set(@user.id, :email => @user.email)

Also it doesn't change original tracker initialization, no need for :action param.

sturgill commented 11 years ago

Yeah, my personal use case (which obviously influenced the direction I took) doesn't have a need to reuse the tracker instance. Every call is basically a once-off called through Resque: there's a single and specific job the tracker is being asked to do.

I also don't completely see why reusing the same tracker instance is advantageous. The format of the request is different enough in the engage API that I actually heavily considered creating a separate class completely and having the Engage and Tracker objects inherit from the same parent class to reuse the Base64 stuff.

I would actually love to see two distinct classes, e.g.

@track = Mixpanel::Tracker.new(TOKEN)
@engage = Mixpanel::Engage.new(TOKEN)

Tracker and Engage would then both be based on a common parent:

module Mixpanel
  class Tracker << Mixpanel
    ...
  end

  class Engage << Mixpanel
    ...
  end
end

and have the Mixpanel::Mixpanel class have the common methods.

Again, it's a matter of style, but I would actually argue that splitting the two makes more sense than keeping them merged. I tried to keep the new code as non-intrusive to the original as possible, but I would actually prefer to see a refactoring of sorts.

But I still think it's just a style thing. And while style is important, I'd rather have this feature part of the official gem sooner than later.

GBH commented 11 years ago

Yeah, I'd prefer doing this:

@mixpanel = Mixpanel.new(TOKEN)
@mixpanel.track('Event')
@mixpanel.engage(:set, @user_id, :email => 'test@example.com')
@mixpanel.import('Event', :foo => 'bar')

Don't know why do you want to initialize new objects for different endpoints though. But yeah, Mixpanel::Tracker currently does too many things. Right now I just need engage method in.

Cheers.

sturgill commented 11 years ago

I think we're pretty much on the same page: neither of us is thrilled with how tracker works, but all we really care about is being able to send something to the engage API.

I would be completely down with your suggested approach: one object and sensibly named methods. Again, my use case only calls one method per object, so my approach above is pretty jaded.

sturgill commented 11 years ago

Had some spare time tonight so I worked through some of this rewrite. See this commit. I made it a new branch on my fork, see here.

I didn't work through async or middleware in case this isn't of interest. But I think it's a lot cleaner... ;)

Sample implementation:

@mixpanel = Mixpanel.new TOKEN
@mixpanel.track 'Event Name', { hash_of_properties }
@mixpanel.import API_KEY, 'Event Name', { hash_of_properties }
@mixpanel.set distinct_id, { hash_of_properties }
@mixpanel.increment distinct_id, { hash_of_properties }

All of these will take an options hash as a final parameter. One of those keys would be :async allowing to set async in the initializer, but change that for a specific action. The track, import, set and increment methods also look for a key called :url to overwrite the default endpoint for each of these methods.

zevarito commented 11 years ago

@sturgill, @GBH,

Overall I like how different API usages are exposed, but there is a small things that we should keep in mind.

I think you both have reached a point where this gem needs to evolve and the discussion you are having here is great, let's polish this work a little bit to complete the refactor and finally deliver a new version.

sturgill commented 11 years ago
zevarito commented 11 years ago

@GBH I've merged your changes and pushed 2.2.0 version of the gem, thanks!

@sturgill Looking forward on your changes, please re-open a new issue to handle that, thanks!

GBH commented 11 years ago

Thanks @zevarito . Looking forward to improvements in 3.0 :)

zevarito commented 11 years ago

Hi @GBH, take a look here https://github.com/zevarito/mixpanel/pull/47