Skip to content

Consider updating library to use pointers for optional fields #56

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

Closed
ojongerius opened this issue Aug 25, 2016 · 16 comments
Closed

Consider updating library to use pointers for optional fields #56

ojongerius opened this issue Aug 25, 2016 · 16 comments
Assignees

Comments

@ojongerius
Copy link
Collaborator

ojongerius commented Aug 25, 2016

Hi there,

So far using default values has worked for us but it will not work in the case where values can either be set or not, and not setting them can influence behaviour.

An example issue issue I ran into require_full_window which is a Boolean, and optional. If the option is not set Datadog uses custom behaviour, which is desirable in some cases.

Using the current API this field defaults to false, which is different to it not being set. I suspect, but have not checked if there are other cases where we ran into this issue.

A solution is to refactor the library to use pointers, as this allows us to check if a value is actually set. The upside is more precision, the downside is that clients using the library now have to do a little more work to use pointers.

A struct like Monitor currently looks like so:

// Monitor allows watching a metric or check that you care about,
// notifying your team when some defined threshold is exceeded
type Monitor struct {
    Creator Creator  `json:"creator,omitempty"`
    Id      int      `json:"id,omitempty"`
    Type    string   `json:"type,omitempty"`
    Query   string   `json:"query,omitempty"`
    Name    string   `json:"name,omitempty"`
    Message string   `json:"message,omitempty"`
    Tags    []string `json:"tags,omitempty"`
    Options Options  `json:"options,omitempty"`
}

And would look like this using pointers for optional fields only:

// Monitor allows watching a metric or check that you care about,
// notifying your team when some defined threshold is exceeded
type Monitor struct {
    Creator *Creator  `json:"creator,omitempty"`
    Id      *int      `json:"id,omitempty"`
    Type    string   `json:"type,omitempty"`
    Query   string   `json:"query,omitempty"`
    Name    *string   `json:"name,omitempty"`
    Message *string   `json:"message,omitempty"`
    Tags    []string `json:"tags,omitempty"`
    Options *Options  `json:"options,omitempty"`
}

Or like so using pointers for all fields:

// Monitor allows watching a metric or check that you care about,
// notifying your team when some defined threshold is exceeded
type Monitor struct {
    Creator *Creator  `json:"creator,omitempty"`
    Id      *int      `json:"id,omitempty"`
    Type    *string   `json:"type,omitempty"`
    Query   *string   `json:"query,omitempty"`
    Name    *string   `json:"name,omitempty"`
    Message *string   `json:"message,omitempty"`
    Tags    []string `json:"tags,omitempty"`
    Options *Options  `json:"options,omitempty"`
}

There are different ways to go about this:

Option Pros Cons
Do nothing No work to be done in library Users have to create their own structs
Pointers for optional only Precision. Less tedious to use than making everything a pointer. Less work to implement. Inconsistent, more work to check which fields are optional
Pointers for all Precision, easier to implement More work for users of library

Will Noris wrote an insightful blogpost about this at go-rest-apis-and-pointers, which relates to his adventures in issue 19 at go-github. Go-github did make the switch to use pointers for all the things, and created helper functions to make using it a little less tedious. The result is not very pleasant to read and use, but it is precise.
There is an interesting discussion making a similar choice in issue 2330 of swagger-api.

I'm leaning toward using pointers for optional fields. @zorkian thoughts?

Cheers,

Otto

@ojongerius
Copy link
Collaborator Author

@zorkian ping!

@zorkian
Copy link
Owner

zorkian commented Sep 11, 2016

Hey this is a fantastic question and thanks for the ping. I agree that we need to support the functionality, but I also think it's ugly as heck. We use lots of protobufs in Go at my dayjob and those get really messy. It's doable and it's fine and it seems to be the way that most APIs go but it leaves me wondering if there's not a better way.

If a field is truly optional then having it be a pointer seems reasonable. That way most of the time the user won't specify it but if they need to they can (with the added and frustrating verbosity). Hmm. Okay so I was messing around in the Playground and am wondering how bad something like this is -- I know the performance is crap but I'm not sure this API is ever used in performance-critical places (may be a pipe dream to wish it wasn't):

https://play.golang.org/p/-LJSAHFY6h

What do you think about that, does it make you super sad? We can even get fancier and use reflect to determine if they've passed things that are names of members of the struct. Whether or not this is a good idea I don't know, but it seems like it might (might) keep the verbosity in the API rather than pushing it to the end-users.

Thoughts?

@nyanshak
Copy link
Collaborator

I think making optional fields use pointers is reasonable. Would it be okay if I made a PR to make Yaxis struct's fields into pointers? Right now when I'm trying to use this, I can't distinguish between Yaxis.Min = 0 and Yaxis.Min = unset, meaning graphs that I'm making end up very broken.

@nyanshak
Copy link
Collaborator

@zorkian I think that something like that code snippet you posted would make optional structs cleaner. I'm not super familiar with Go style, so I don't know how other libraries have handled the same situation. That said, it looks like a good solution.

(to be clear, referring to this snippet: https://play.golang.org/p/-LJSAHFY6h)

@zorkian
Copy link
Owner

zorkian commented Jan 23, 2017

We should circle back to this and figure out what we want to do given that there's another request open #75 related to this.

@zorkian
Copy link
Owner

zorkian commented Jan 23, 2017

Given:

I propose:

  • We cut the current version (or a very soon version) of go-datadog-api and branch it onto a v1 branch and then stop touching it, with caveats that some things are known-broken (such as JSON Marshalling of User Booleans Not Working Correctly #75) and can't be fixed,
  • We start development on a v2 (on master) and convert all fields to pointer types, and create helpers as necessary to make things easy to work with.

While I don't like the idea of pointer fields everywhere, it's at least something we're used to and seems to be a reasonable way of moving forward.

Thoughts on this? Any changes/suggestions?

@nyanshak
Copy link
Collaborator

I agree with the approach proposed (cut current(ish) version and start v2 branch), but I'd suggest some additional changes to more completely deal with the API quirks.

One example is that certain fields are optional, but also can be either a number or a string (which is a number) depending on which graph type they're included in. It's late here and I don't have my notes around, but it's something like:

# For a change graph
{
...
  "some_field": 1 // this one is a number
}

# For a timeseries graph
{
...
  "some_field": "1" // this one is a string number
}

I had previously submitted PRs to change from json.Int (or float) to json.Number in some cases, but I imagine this (v2 branch creation) would be an appropriate time to make these breaking changes.

@combor
Copy link

combor commented Jan 25, 2017

Hi,

I'd like to 👍 for fixing this issue as we hit it as well while working on alphagov/paas-cf#738. We are going to implement some dirty workaround in the meantime by using curl and API directly to update require_full_window which we need to be set to false.
Do you have any timeframe when it comes to implementing changes? Can we help somehow?

@zorkian
Copy link
Owner

zorkian commented Jan 25, 2017

I was letting ~enough time to go by for any objections/feedback but haven't heard anything, so let's go ahead with the plan to switch everything to pointers and cut it as v2. I'm at my day-job right now and won't have time to work on this today, so if you're particularly motivated you can start the conversion and we can review it.

If not, I should have time sometime within the next week to do the work.

@combor
Copy link

combor commented Jan 26, 2017

Cool, I'm busy as well this week but I might be able to do sth this weekend. No promises though :)

@ojongerius
Copy link
Collaborator Author

Just got off a 3 hour flight and have a rough cut I should be able to push out before the weekend.

@ojongerius ojongerius self-assigned this Jan 26, 2017
combor pushed a commit to alphagov/paas-cf that referenced this issue Jan 26, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
combor pushed a commit to alphagov/paas-cf that referenced this issue Jan 26, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
combor pushed a commit to alphagov/paas-cf that referenced this issue Jan 26, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
combor pushed a commit to alphagov/paas-cf that referenced this issue Jan 26, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
combor pushed a commit to alphagov/paas-cf that referenced this issue Jan 26, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
mtekel added a commit to alphagov/paas-docker-cloudfoundry-tools that referenced this issue Jan 26, 2017
Because of issue[1] with datadog library used by TF datadog provider,
we need to run additional scripts after TF run to finish up configuration.
These scripts are written in ruby and require dogapi gem. Modify TF
container to be based on ruby:alpine and add dogapi gem.

[1] zorkian/go-datadog-api#56
ojongerius added a commit that referenced this issue Jan 27, 2017
@ojongerius
Copy link
Collaborator Author

ojongerius commented Jan 27, 2017

Have raised #83 as proof of concept. See my notes in the PR, happy to discuss either here or there!

mtekel added a commit to alphagov/paas-cf that referenced this issue Jan 27, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply false
require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
combor pushed a commit to alphagov/paas-cf that referenced this issue Jan 27, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
combor pushed a commit to alphagov/paas-cf that referenced this issue Jan 27, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply false
require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
combor pushed a commit to alphagov/paas-cf that referenced this issue Jan 27, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
mtekel added a commit to alphagov/paas-cf that referenced this issue Feb 1, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply
`false` require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
mtekel pushed a commit to alphagov/paas-cf that referenced this issue Feb 2, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
mtekel added a commit to alphagov/paas-cf that referenced this issue Feb 2, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply
`false` require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
mtekel pushed a commit to alphagov/paas-cf that referenced this issue Feb 2, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.
mtekel added a commit to alphagov/paas-cf that referenced this issue Feb 2, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply
`false` require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
combor pushed a commit to alphagov/paas-cf that referenced this issue Feb 2, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.

Also, as ruby library for DataDog api is re-creating a
monitor every time it does update we need to send all options that were
previously set for the monitor to not fallback to monitor defaults.
combor pushed a commit to alphagov/paas-cf that referenced this issue Feb 2, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply
`false` require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
mtekel pushed a commit to alphagov/paas-cf that referenced this issue Feb 2, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.

Also, as ruby library for DataDog api is re-creating a
monitor every time it does update we need to send all options that were
previously set for the monitor to not fallback to monitor defaults.
mtekel added a commit to alphagov/paas-cf that referenced this issue Feb 2, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply
`false` require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
dcarley pushed a commit to alphagov/paas-cf that referenced this issue Feb 3, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.

Also, as ruby library for DataDog api is re-creating a
monitor every time it does update we need to send all options that were
previously set for the monitor to not fallback to monitor defaults.
dcarley pushed a commit to alphagov/paas-cf that referenced this issue Feb 3, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply
`false` require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
dcarley pushed a commit to alphagov/paas-cf that referenced this issue Feb 3, 2017
Since we have discovered that go-datadog library has problems with
setting default options for some monitor
settings(zorkian/go-datadog-api#56) we need to
use this script to ensure all options that we care about have desired
values.

Also, as ruby library for DataDog api is re-creating a
monitor every time it does update we need to send all options that were
previously set for the monitor to not fallback to monitor defaults.
dcarley pushed a commit to alphagov/paas-cf that referenced this issue Feb 3, 2017
Because of datadog go library issue
(zorkian/go-datadog-api#56) we need to apply
`false` require_full_window attributes in additional step after terraform.

This can be reverted once datadog library is fixed and DataDog TF provided
uses fixed library.
@ojongerius
Copy link
Collaborator Author

Copy of the most part of my comment in #83, so people know what's up with this issue:

I've coded something up that generates SetXx, HasXx, GetXx and GetXxOk. Using it would look like:

	m := datadog.Monitor{}
	c := datadog.Creator{}
	
        // Use SetXx:
        c.SetName("Joe Creator")
	m.SetName("Monitor all the things")
	m.SetMessage("Fat electrons in the lines")

	// Use HasXx:
	if m.HasMessage() {
		fmt.Printf("Found message %s\n", m.GetMessage())
	}

	// Or maybe you prefer a tuple with the value and a boolean if it was ever set
        // and use GetXxOk
	if v, ok := m.GetMessageOk() ; ok {
		fmt.Printf("Found message %s\n", v)
	}

I still like having the other helpers around, and keep support for doing:

	// You could still initialize the struct in one swoop
	_ = datadog.Monitor{
		Name: datadog.String("Monitor other things"),
		Creator: &datadog.Creator{
			Name: datadog.String("Joe Creator"),
		},
	}

I'll push up some changes to this PR hopefully today, else tomorrow.

@ojongerius
Copy link
Collaborator Author

Pushed changes up, see #83

ojongerius added a commit that referenced this issue Feb 18, 2017
…ields

WIP GH-56 Refactor to use pointers for all fields.
@ojongerius
Copy link
Collaborator Author

ojongerius commented Feb 18, 2017

#83 has been merged 🎉

Do note that this has been merged to v2, which you can use by importing import "gopkg.in/github.com/zorkian/go-datadog-api.v2". Well wait with cutting the main branch over to this one. See https://github.com/zorkian/go-datadog-api/blob/v2/README.md

stack72 pushed a commit to hashicorp/terraform that referenced this issue Feb 20, 2017
* provider/datadog: Pulls v2 and removes v1 of library go-datadog-api.

    See zorkian/go-datadog-api#56 for context.

    * Fixes bug in backoff implementation that decreased performance significantly.
    * Uses pointers for field types, providing support of distinguishing
        between if a value is set, or the default value for that type is
        effective.

* provider/datadog: Convert provider to use v2 of go-datadog-api.

* provider/datadog: Update vendored library.

* provider/datadog: Update dashboard resource to reflect API updates.
stack72 pushed a commit to hashicorp/terraform that referenced this issue Feb 20, 2017
* provider/datadog: Pulls v2 and removes v1 of library go-datadog-api.

    See zorkian/go-datadog-api#56 for context.

    * Fixes bug in backoff implementation that decreased performance significantly.
    * Uses pointers for field types, providing support of distinguishing
        between if a value is set, or the default value for that type is
        effective.

* provider/datadog: Convert provider to use v2 of go-datadog-api.

* provider/datadog: Update vendored library.

* provider/datadog: Update dashboard resource to reflect API updates.
grubernaut pushed a commit to DataDog/terraform-provider-datadog that referenced this issue Jun 6, 2017
* provider/datadog: Pulls v2 and removes v1 of library go-datadog-api.

    See zorkian/go-datadog-api#56 for context.

    * Fixes bug in backoff implementation that decreased performance significantly.
    * Uses pointers for field types, providing support of distinguishing
        between if a value is set, or the default value for that type is
        effective.

* provider/datadog: Convert provider to use v2 of go-datadog-api.

* provider/datadog: Update vendored library.

* provider/datadog: Update dashboard resource to reflect API updates.
camelpunch added a commit to alphagov/paas-cf that referenced this issue Feb 1, 2018
Effectively a revert of 8e12c13. The upstream go library issue has now
been fixed:

zorkian/go-datadog-api#56

This addresses #1170
camelpunch added a commit to alphagov/paas-cf that referenced this issue Feb 1, 2018
Effectively a revert of 8e12c13. The upstream go library issue has now
been fixed:

zorkian/go-datadog-api#56

This addresses #1170
camelpunch added a commit to alphagov/paas-cf that referenced this issue Feb 5, 2018
Effectively a revert of 8e12c13. The upstream go library issue has now
been fixed:

zorkian/go-datadog-api#56

This addresses #1170
camelpunch added a commit to alphagov/paas-cf that referenced this issue Feb 8, 2018
Effectively a revert of 8e12c13. The upstream go library issue has now
been fixed:

zorkian/go-datadog-api#56

This addresses #1170
dcarley pushed a commit to alphagov/paas-cf that referenced this issue Feb 9, 2018
Effectively a revert of 8e12c13. The upstream go library issue has now
been fixed:

zorkian/go-datadog-api#56

This addresses #1170
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

No branches or pull requests

4 participants