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

Refactoring Monitor type #30

Closed
2 tasks done
haya14busa opened this issue Nov 18, 2016 · 3 comments
Closed
2 tasks done

Refactoring Monitor type #30

haya14busa opened this issue Nov 18, 2016 · 3 comments

Comments

@haya14busa
Copy link
Contributor

haya14busa commented Nov 18, 2016

Problem

Currently, type Monitor represents all monitor types, so required fields for each monitor type are unclear.
Also, JSON tag must have omitempty because of above reason.

Solution

Define each monitor type and Monitor interface.

type Monitor interface {
	MonitorType() string // MonitorType() must return monitor type (e.g. connectivity, host, etc...).
}
const (
	monitorTypeConnectivity  = "connectivity"
        // ...
)

// MonitorConnectivity represents connectivity monitor.
type MonitorConnectivity struct {
	ID                   string `json:"id,omitempty"`
	Name                 string `json:"name,omitempty"`
	Type                 string `json:"type,omitempty"`
	IsMute               bool   `json:"isMute,omitempty"`
	NotificationInterval uint64 `json:"notificationInterval,omitempty"`

	Scopes        []string `json:"scopes,omitempty"`
	ExcludeScopes []string `json:"excludeScopes,omitempty"`
}

func (m *MonitorConnectivity) MonitorType() string {
	return monitorTypeConnectivity
}
// ...

func (c *Client) FindMonitors() ([]Monitor, error) {
  // ...
}
func (c *Client) CreateMonitor(param Monitor) (Monitor, error) {
  // ...
}
func (c *Client) DeleteMonitor(monitorID string) (Monitor, error) {
  // ...
}

Users can use type switch to access each monitor type like below.

var monitor Monitor = &MonitorConnectivity{}
switch m := monitor.(type) {
  case *MonitorConnectivity:
    fmt.Println(m.Name)
      // ...
}

We also needs to handle decoding JSON to each monitors types.
I'm considering to handle this problem by executing unmrashaling twice (1. looking for "type" field and 2. decoding to the monitor type) or decoding to map[string]interface{} once and converting it to each monitor type with "type" value using mitchellh/mapstructure.

Pull-Request plan

  • Introduce monitor interface as unexported name and each monitor type structs.
  • Handle JSON decoding and change interface to use new Monitor interface (breaking changes)

Possible additional actions after above works:

  • Remove inappropriate omitempty tag in each monitor types
  • Add additional method of Mointor interface (e.g. add .GetID() which returns monitor id). Common keys of monitor JSON are id, name, type, isMute, and notificationInterval.
    • but i think we don't need to add every methods to return value of common key. Thease values often are not enough and users can get each type by type switch.
@haya14busa
Copy link
Contributor Author

haya14busa commented Nov 18, 2016

monitors JSON decoding

I implemented two decoding method and run benchmark.

  1. method 1: executing unmrashaling twice (1. looking for "type" field and 2. decoding to the monitor type)
  2. method 2: decoding to map[string]interface{} once and converting it to each monitor type with "type" value using mitchellh/mapstructure.

diff: master...haya14busa:refactor-monitor-type-json

$ go test -v -count=10 -run="^$" -bench=Monitor_JSON_ | benchstat
name                         time/op
Monitor_JSON_mapstructure-4   159µs ± 1%
Monitor_JSON_rawmessage-4    95.2µs ± 6%

Benchmark for larger JSON

$ wc -c monitors.json
24802
$ # change test JSON to monitors.json
$ go test -v -run="^$" -bench=Monitor_JSON_ | prettybench
benchmark                              iter    time/iter
---------                              ----    ---------
BenchmarkMonitor_JSON_mapstructure-4   1000   1.98 ms/op
BenchmarkMonitor_JSON_rawmessage-4     1000   1.40 ms/op

I suspected that method 1. might be slow because it needs additional unmarshaling JSON, but bench shows it's faster than method 2 (though both implementations are fast enough, i guess).
method 2 also has downside which requires external package dependencies other than go standard lib.

So, I'll implement method 1 to handle decoding JSON.

@haya14busa
Copy link
Contributor Author

All main refactoring tasks are done! 🎉

As a follow up, we can remove needless omitempty tag for each monitor types.

But, I think this issue is closable. Removing omitempty tag is not an urgent task.
I (or you) can remove them one by one when we have a time.

@itchyny
Copy link
Contributor

itchyny commented Nov 28, 2016

Thank you for your great contribution! 👍

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

2 participants