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

Add boilerplate for api, commands, kvstore access and job management #212

Open
wants to merge 9 commits into
base: master
Choose a base branch
from

Conversation

BenCookie95
Copy link
Contributor

@BenCookie95 BenCookie95 commented Nov 8, 2024

Summary

Problem:
The starter template is too bare bones to kickstart most plugin efforts, requiring a lot of copy and paste from “known good” plugins to achieve a stable starting point.

Justification:
DE doesn’t use the starter template all that often anymore, spending extra time bootstrapping a plugin with all the necessary plumbing. This also leads to unnecessary divergences between plugins, complicating our developer integration strategy and story.

I added some skeleton code for creating an api and adding new slash commands. I separated the slash commands and KVStore access into their own packages for ease of use. I also added a simple mock for the command package to show how these separate packages can be easily tested.

I noticed we used this Job Manager code across a few different plugins and I thought it would be very useful to bring into the skeleton.

Ticket Link

https://mattermost.atlassian.net/browse/MM-61468
https://mattermost.atlassian.net/browse/MM-60911
https://mattermost.atlassian.net/browse/MM-60910
https://mattermost.atlassian.net/browse/MM-60909

Copy link
Contributor

@hanzei hanzei left a comment

Choose a reason for hiding this comment

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

I really appreciate the work you are doing for the starter template. This is a great way for community members to build plugins more easily.

I wonder if we should make the boilerplate code opt-in. Something like a cli tool that generates a fresh repo with all the code that was specified. go templates could drive such a CLI tool.

@BenCookie95
Copy link
Contributor Author

BenCookie95 commented Nov 11, 2024

I really appreciate the work you are doing for the starter template. This is a great way for community members to build plugins more easily.

I wonder if we should make the boilerplate code opt-in. Something like a cli tool that generates a fresh repo with all the code that was specified. go templates could drive such a CLI tool.

Go templates is a great suggestion and maybe something we can use in future! I know that too much boilerplate can be annoying but I think this current implementation is easy to manage because most stuff is separated into separate packages and it's just a case of deleting the package and the initialization logic in plugin.go.

@BenCookie95 BenCookie95 changed the title WIP: Add boilerplate for api, commands and jobs Add boilerplate for api, commands, kvstore access and job management Nov 13, 2024
Copy link
Member

@lieut-data lieut-data left a comment

Choose a reason for hiding this comment

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

Thanks, @BenCookie95! A few of my inline comments are more exploratory and aren't blocking, but a few high level thoughts I'd love to work through:

  • I'm not a big fan of packages for packages sake, e.g. configuration. Similarly, command, and especially the resulting interface just makes navigating the code all that much harder. Could we hoist some of the common code into the public package and make this simple enough to have all the code live in the main package?
  • The job manager feels like it comes with a lot of baggage that I'd love to avoid adding to the template. Could we illustrate running an HA-aware job using the existing cluster package instead?

router.ServeHTTP(w, r)
}

func (p *Plugin) MattermostAuthorizationRequired(next http.Handler) http.Handler {
Copy link
Member

Choose a reason for hiding this comment

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

It would be awesome to hoist this into the public package.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah that makes sense

server/api.go Outdated Show resolved Hide resolved
server/command/command.go Outdated Show resolved Hide resolved
const helloCommandTrigger = "hello"

// Register all your slash commands in the NewCommandHandler function.
func NewCommandHandler(client *pluginapi.Client) Command {
Copy link
Member

Choose a reason for hiding this comment

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

One day, it would be awesome to hoist this into the public package and just register callbacks for the slash commands to be handled.

In that future, I wonder if we would need a discrete package at all and could just do this all in command.go?

Comment on lines 26 to 28
AutoComplete: true,
AutoCompleteDesc: "Say hello to someone",
AutoCompleteHint: "<username>",
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if we should illustrate the advanced autocomplete functionality?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

What is that advanced functionality? I'm not aware, is there something I can read?

Copy link
Member

Choose a reason for hiding this comment

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

server/jobs/jobs_util.go Outdated Show resolved Hide resolved
server/jobs/startertemplate_job.go Outdated Show resolved Hide resolved
server/jobs/startertemplate_job.go Outdated Show resolved Hide resolved
server/plugin.go Outdated Show resolved Hide resolved
server/plugin.go Outdated Show resolved Hide resolved
@lieut-data
Copy link
Member

I know that too much boilerplate can be annoying but I think this current implementation is easy to manage because most stuff is separated into separate packages and it's just a case of deleting the package and the initialization logic in plugin.go.

👍 to just having code vs. generating. That being said, as noted above, I'm not a huge fan of packages achieve this, so hopefully we can find a middle ground where it's still easy to remove but doesn't come with lots of cognitive overhead in the way the plugin is structured.

@BenCookie95
Copy link
Contributor Author

BenCookie95 commented Nov 13, 2024

I'm not a big fan of packages for packages sake, e.g. configuration. Similarly, command, and especially the resulting interface just makes navigating the code all that much harder. Could we hoist some of the common code into the public package and make this simple enough to have all the code live in the main package?

My main thought process of creating separate packages from the start was to discourage the overuse of the main package. I've read through a bunch of plugins and it gets very hard to navigate or figure out where anything is when it lives in the main package. You mentioned that you aren't a fan of using packages due to the cognitive overhead in the way the plugin is structured. Am I alone in wanting more packages to achieve this? I personally find it much easier to read and navigate.

I agree that I could move the config back into the main package because it doesn't serve much use as it's own package (probably went overboard with that one). Command in it's current state made sense to be in a separate package because there is a fair amount of boilerplate to work through. I'll take a look at hoisting some of that to the public package and then it would probably make sense to move it back to main?

The job manager feels like it comes with a lot of baggage that I'd love to avoid adding to the template. Could we illustrate running an HA-aware job using the existing cluster package instead?

Yeah, my initial thoughts were from a DE perspective because this was reused in a few plugins but it's overkill for a contributor coming in. I'll simplify it. Demo plugin already has a simple use of the cluster package that I will re-use

@BenCookie95
Copy link
Contributor Author

Resolved most of the comments. Removed the config package and cleared out the overly complicated Job stuff

@lieut-data
Copy link
Member

My main thought process of creating separate packages from the start was to discourage the overuse of the main package. I've read through a bunch of plugins and it gets very hard to navigate or figure out where anything is when it lives in the main package. You mentioned that you aren't a fan of using packages due to the cognitive overhead in the way the plugin is structured. Am I alone in wanting more packages to achieve this? I personally find it much easier to read and navigate.

@BenCookie95, for context, I recently went through an exercise in MS Teams collapsing many of the packages back into the main package. Most of the secondary packages were tightly coupled with the Plugin and required lots of interface juggling when more complex business logic was required. I was able to eliminate maybe 25% of the code overhead and make the code easier to navigate without unhelpful interfaces. I'm curious how you might find reading https://github.com/mattermost/mattermost-plugin-msteams/tree/main/server (not that it's perfect by any stretch!)

On the "when" side for new packages, I was chatting with @crspeller and wrote down a few shared thoughts:

  • Fewer packages is better: default to the main package unless there's good reason for a new package.
  • Coupling implies same package: don't jump through hoops to break apart code that's naturally coupled.
  • New package for a new interface: a classic example is the sqlstore with layers for monitoring performance, caching and mocking.
  • New package for upstream integration: a discrete client package for interfacing with a 3rd party is often a great place to break out into a new package

Curious as to your thoughts?

Copy link
Member

@lieut-data lieut-data left a comment

Choose a reason for hiding this comment

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

Thanks @BenCookie95! One comment about the commented code, but otherwise non-blocking.

Comment on lines 26 to 28
AutoComplete: true,
AutoCompleteDesc: "Say hello to someone",
AutoCompleteHint: "<username>",
Copy link
Member

Choose a reason for hiding this comment

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

server/configuration.go Outdated Show resolved Hide resolved
server/plugin.go Outdated Show resolved Hide resolved
server/job.go Show resolved Hide resolved
server/api.go Show resolved Hide resolved
@BenCookie95
Copy link
Contributor Author

My main thought process of creating separate packages from the start was to discourage the overuse of the main package. I've read through a bunch of plugins and it gets very hard to navigate or figure out where anything is when it lives in the main package. You mentioned that you aren't a fan of using packages due to the cognitive overhead in the way the plugin is structured. Am I alone in wanting more packages to achieve this? I personally find it much easier to read and navigate.

@BenCookie95, for context, I recently went through an exercise in MS Teams collapsing many of the packages back into the main package. Most of the secondary packages were tightly coupled with the Plugin and required lots of interface juggling when more complex business logic was required. I was able to eliminate maybe 25% of the code overhead and make the code easier to navigate without unhelpful interfaces. I'm curious how you might find reading https://github.com/mattermost/mattermost-plugin-msteams/tree/main/server (not that it's perfect by any stretch!)

On the "when" side for new packages, I was chatting with @crspeller and wrote down a few shared thoughts:

  • Fewer packages is better: default to the main package unless there's good reason for a new package.
  • Coupling implies same package: don't jump through hoops to break apart code that's naturally coupled.
  • New package for a new interface: a classic example is the sqlstore with layers for monitoring performance, caching and mocking.
  • New package for upstream integration: a discrete client package for interfacing with a 3rd party is often a great place to break out into a new package

Curious as to your thoughts?

I'm happy with that criteria you laid out and I think I'll add it to the README of this plugin so contributors have some guidance. Thanks!

required lots of interface juggling when more complex business logic was required

I can see how that can be painful if overused

@hanzei hanzei added the 2: Dev Review Requires review by a core committer label Dec 5, 2024

This is a central place for you to access the KVStore methods that are available in the `pluginapi.Client`. The package contains an interface for you to define your methods that will wrap the KVStore methods. An instance of the KVStore is created in the `OnActivate` hook.

#### Jobs package
Copy link
Member

Choose a reason for hiding this comment

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

Not a package anymore.

Copy link
Member

@wiggin77 wiggin77 left a comment

Choose a reason for hiding this comment

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

LGTM 👍 One change needed to readme.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
2: Dev Review Requires review by a core committer
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants