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

Create guide on how to create plugins #1429

Merged
merged 3 commits into from
Oct 29, 2018

Conversation

cburgdorf
Copy link
Contributor

@cburgdorf cburgdorf commented Oct 25, 2018

What was wrong?

For people to start contributing Trinity plugins or building their own applications with the Trinity + Plugins Model we need to do a good job of teaching them how to use the Plugin API. So we need a detailed guide for the Plugin API. Notice that this PR is a spin off from #1424 to allow #1424 to get merged sooner while I take more time for writing the guide.

How was it fixed?

This is a draft version that we may merge anyway to have something for DEVCON !V

trinity_plugins_guide

Cute Animal Picture

put a cute animal picture link inside the parentheses

different for a :class:`~trinity.extensibility.plugin.BaseMainProcessPlugin` but fairly similar
for the other types of plugins which we'll be focussing on for now.

Plugins need to implement the :meth:`~trinity.extensibility.plugin.BasePlugin._start` method
Copy link
Contributor Author

Choose a reason for hiding this comment

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

@pipermerriam remember when we talked about the _start / start pair where start is calling _start and _start is meant to be implemented whereas start is meant to be called because it does some work and then delegates to _start behind the scenes. #1331 (comment)

The naming of _start is proving to be problematic from a documentation standpoint because it is considered a private API and those are by default not being considered for the docs (rightfully so). This also means that linking to them won't work.

I wonder if we can find a generic pattern for this where we derive a name similar to the public API name but without making it private. I think this is not only good from a documentation standpoint but it also strikes me as the right thing to do. We use the same pattern in the BaseService so it would be nice if we can find a generic naming convention. E.g.

start -> do_start
stop -> do_stop
...

I'm usually bad at naming but I kinda like the do prefix. Thoughts? /cc @carver

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Btw, no need to review the rest of the PR. I just put it out for transparency but the whole text, structure is still very rough, incomplete and in flux.

Copy link
Member

Choose a reason for hiding this comment

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

do_start seems fine. You could also invert these and make _start the one that is called internally and start the one that the user implements.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You could also invert these

That would work for the implementation as of today where Plugins call start themselves but I would still consider both APIs public. It is more clear for the stop API that is called from the PluginManager hence it is definitely public.

But if you are ok with the do prefix then I'll send a PR for that. Thinking about it, it was strange to have a method that is intended to be overwritten to be private anyway. That wouldn't even work in most languages (e.g. Java, C# etc)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Linking #1440

Copy link
Member

Choose a reason for hiding this comment

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

@cburgdorf as stated in the other PR, I'm fine with the do_ prefix on the plugin API but I'm 👎 on immediately extending it to the rest of the codebase.

Copy link
Contributor Author

@cburgdorf cburgdorf Oct 26, 2018

Choose a reason for hiding this comment

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

but I'm -1 on immediately extending it to the rest of the codebase.

@pipermerriam is this because we need to find a better prefix than do? Because, from a language theory it strikes me as plain wrong that we have something like BaseService._run as private and abstract at the same time. In fact, I don't know any statically typed language (which Python isn't but there more we use mypy the more we try to be haha) that would allow this.

In something like Java or C#, if you want subclasses to be able to overwrite a method, or even force them to, then that method can not be private.

And it has real consequences, it means that if we document the BaseService like this:

.. autoclass:: p2p.service.BaseService
  :members:

Then, _run and _cleanup, probably the most important methods of this class, those that need to be overwritten, simply fall out of the documentation because they are incorrectly seen as private. Something that would be impossible in most if not all statically typed language that have the concepts of private members and inheritance.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Btw, I would be seam totally reasonable to me if in the future mypy would raise warnings or even errors for when private members are overwritten in subclasses. On the naming part, here are two alternatives for prefixes:

  • protected_ (borrowed from the access modifier that Java, C# and TypeScript use for members that are accessible in subclasses but not from other classes which kinda goes nicely hand in hand with our intend)
  • sealed_ just because it is a little shorter and seems to convey the same as the former

Copy link
Contributor

Choose a reason for hiding this comment

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

I think what we're struggling with here is that a bad architectural design is triggering a negative side-effect of some weird OOP practices (this private/protected method that must be implemented by subclasses).

Two types of needs call for two types of solutions:

  1. Urgent feature: patch the side effect by adding do_ (I think Christoph feels urgency on the plugin docs, so they are in this category)
  2. Easy maintenance: attack the root architectural problem, probably with converting inheritance to compositional approach. (I think BaseService and other instances in the code base
    are in this category)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Added my answer in the PR. #1440 (comment)

These methods were named so that they appeared
private by convention. This convention causes
trouble in the documentation where these methods
are righfully dropped. Since these methods aren't
really private in reality (they need to be overwritten
in subclasses), they were renamed, migrating their
naming from `_*` to `do_*`.
This enables the plugin to read the status of the
four formal states a plugin can be in. Previously
even though the four states existed implicitly,
it could only be differentiated between the
STARTED/STOPPED state based on the `running`
bool.

This change also has the nice benefit that we
can make stronger assumptions about the status
inside `start()` and raise an exception if
`start()` was called on a plugin that isn't in
the correct status to call `start()`
@cburgdorf cburgdorf force-pushed the christoph/docs/plugin-guide branch 3 times, most recently from 6299f3a to b7168be Compare October 28, 2018 22:32
@cburgdorf cburgdorf merged commit 455678e into ethereum:master Oct 29, 2018
@cburgdorf
Copy link
Contributor Author

Merged this without review as discussed with @pipermerriam in the chat to get the draft guide up online for DEVCON IV.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants