Skip to content

[RFC] Introduce "semantics": a way to make service ids meaningful by binding them to types+descriptions #27207

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
nicolas-grekas opened this issue May 9, 2018 · 11 comments · Fixed by #28970
Labels
RFC RFC = Request For Comments (proposals about features that you want to be discussed)

Comments

@nicolas-grekas
Copy link
Member

nicolas-grekas commented May 9, 2018

Introduction

Some service ids are more important than others: they are like entry points for the features provided by core or third party bundles (or the app itself). Yet, we are missing a way to reliably identify them amongst all the other service ids that are here just to make things work.

The debug:container command used to use the public/private concept as a way to make this distinction, but now that all/most services are private, we know this was a broken hack (which has been removed in 4.1). Autowiring gave us a different perspective on the topic: the aliases we added to make it work are some of these meaningful identifiers. But there are more, like all the cache pools that users define in their configuration, or command buses, or logger channels, etc. - all sort of non-autowireable services that are still part of the useful services for users.

In #26142, @weaverryan tried to introduce "key services". This is another hint we're missing something, like a blind spot for a concept we didn't grasp yet. I'd like to introduce you to "semantics", which is a proposal I brainstormed about with @tgalopin and that IOHO could fill this hole.

Semantics

These meaningful services have 3 properties that make them special:

  • their id convey semantics: it is a meaningful string that hints the purpose of the service (e.g. "logger", or "bus.command", etc.);
  • we want to be able to enforce their type, so that 1. their id is bound to an abstraction and 2. they are made easy to discover and type-hint for;
  • their purpose is documented, so that people can know why and when they should use any of them.

These 3 properties should be independent from the actual definition of the services that provide them. For this reason, we need something new, independent from Alias and Definition instances.

Given these contraints and definitions, the proposal is to make "semantics" a first class concept.
Technically, one could create them like that:

Using the ContainerBuilder directly:

$container->setSemantics(string $id, array $types, string $description = null);

Using yaml:

semantics:
  cache.forecast:
    types: [Psr\Cache\CacheItemPoolInterface, Symfony\Component\Cache\Adapter\AdapterInterface]
    description: The cache pool where forecast-related items should be stored.

(the listed types should inherit from each others, so that this wouldn't allow creating new types that don't exist in PHP.)

Use cases

Provided with this additional semantics, we'll be able to:

This should not incur any burden on regular users as the concept should be manipulated only by bundle authors.

@nicolas-grekas nicolas-grekas added the RFC RFC = Request For Comments (proposals about features that you want to be discussed) label May 9, 2018
@linaori
Copy link
Contributor

linaori commented May 9, 2018

I see potential here, I'm just not sure of how this would solve the autowiring issue with multiple interfaces.

[edit: see https://github.com//pull/27172#issuecomment-387812626]

@teohhanhui
Copy link
Contributor

"Semantic" is an adjective, not a noun. The noun is "semantics".

@weaverryan
Copy link
Member

I really like this! And I really like it as a separate concept from Definitions & Aliases. This would give me what I need to create a better debug:container command.

Could each semantic id be tied to multiple interfaces? For example, cache.app actually has 2 different alias interfaces that point to it. Each interface will actually have its own description. The YAML seems like it supports this, but $container->setSemantic() didn't quite look right yet (these are details...).

@stof
Copy link
Member

stof commented May 9, 2018

yeah, the suggest YAML fomat is inconsistent with the PHP API, as it uses a map of type to description. To map to the suggested PHP API, it should has 2 childs: type and description.

@nicolas-grekas
Copy link
Member Author

Could each semantic id be tied to multiple interfaces?

I think yes, but with a restriction: the listed interfaces should inherit from each other. It should not be possible to list unrelated interfaces there, because this would kinda define a new type that wouldn't exist in the code. Description updated.

@stof
Copy link
Member

stof commented May 9, 2018

but then, does it even make sense to list multiple ones ? Listing the child one should be enough, no ?

@nicolas-grekas
Copy link
Member Author

Technically, it would be enough, but I think it would be important to be able to select which interfaces are really the meaningful ones amongst the parents, so that we can build a better command line out of this info. That's quite similar to the fact that we create only selected aliases for autowiring. Does that make sense?

@michellesanver
Copy link

I just yesterday thought about how there currently is not an intuitive solution for this problem, this seems pretty straight forward and logical. I like it! I think with semantics the idea is to be very explicit about it all, so listing all the meaningful interfaces does make sense in my eyes. It also accidentally on purpose documents a part of the documentation that currently is looking a little bit like magic.

@michellesanver
Copy link

I’m going to work on this RFC as my first core contribution, with the mentoring of my knowledgeable colleagues at Liip 💚

It will take a little time to get into everything, I’ll start on Monday 👍

@michellesanver
Copy link

michellesanver commented May 30, 2018

Just an update so you know, since I said I would get started: I got sick and had to prioritise other work when I got back on track, but I reserved some days to work on it now 👍

@nicolas-grekas
Copy link
Member Author

Should be fixed completely differently by #28970 - see description there.

nicolas-grekas added a commit that referenced this issue Oct 29, 2018
…rvices and their description (nicolas-grekas)

This PR was merged into the 4.2-dev branch.

Discussion
----------

[FrameworkBundle] make debug:autowiring list useful services and their description

| Q             | A
| ------------- | ---
| Branch?       | 4.2
| Bug fix?      | yes
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | #27207
| License       | MIT
| Doc PR        | -

This PR closes #27207: we don't need "semantics" anymore. 4.2 has everything already to allow us to separate useful services from the other ones: any autowireable *alias* **is** a useful service!
Add autowiring by type + parameter name (#28234) and the story is done: we can easily hint people about which features their bundles provide, without being polluted by for-wiring-only services.

Here is a screenshot running this command(before I excluded the aliases for $cacheApp and $cacheSystem):
![image 3](https://user-images.githubusercontent.com/243674/47437006-f41f4380-d7a7-11e8-9f76-7f23e9193ce8.png)

ping @weaverryan as we drafted that together.
Fixes a few issues found meanwhile.
That should definitely go in 4.2.

Commits
-------

56aab09 [FrameworkBundle] make debug:autowiring list useful services and their description
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
RFC RFC = Request For Comments (proposals about features that you want to be discussed)
Projects
None yet
6 participants