On Service Names and Documentation

140 views
Skip to first unread message

Paul M. Jones

unread,
Apr 20, 2014, 7:11:17 PM4/20/14
to aur...@googlegroups.com
Hi all,

Two issues have been at the back of my mind regarding service names, and now is the time to bring them up. These issues are related to each other.

First, it's hard to tell what services a package defines, and which ones it modifies. In order to find that out, you need to walk through the configuration `define()` code and examine it directly for `$di->set(...)` calls, and the then examine the `modify()` code for `$di->get()` code.

Second, we currently name shared services in a project container pretty loosely. We have a "logger", a "web_responder", "cli_dispatcher", and so on. This loose naming means it may be tough to combine services from different packages. If VendorFoo.Package creates a "zim" service and VendorBar.Package also creates a "zim" service then they will be in conflict.

I'd like to discuss our options related to these two issues.

* * *

I think the second problem is the easier one to solve. I propose that from here on we name services *for the package in which they are defined*. The service name should begin with the Composer-style package name, be followed by a colon, and then match ([A-Za-z][A-Za-z0-9_]*) in the name (so that the latter part can mimic variable name).

For example, the Aura.Web_Kernel package currently defines four services:

- `$di->set('web_request', ...)`
- `$di->set('web_response', ...)`
- `$di->set('web_router', ...)`
- `$di->set('web_dispatcher', ...)`

Under the new proposal for names, they would become:

- `$di->set('aura/web-kernel:request', ...)`
- `$di->set('aura/web-kernel:response', ...)`
- `$di->set('aura/web-kernel:router', ...)`
- `$di->set('aura/web-kernel:dispatcher', ...)`

FWIW, I tried several variations, and this is the one that looks least like a class name. Because project config files will have a mix of class name references and service name references, I want them to be easily distinguishable. The other variations included ...

- Aura\Web_Kernel\(Response|Request|Router|Dispatcher)
- Aura\Web_Kernel:(response|request|router|dispatcher)
- Aura\Web_Kernel.(response|request|router|dispatcher)
- Aura.Web_Kernel.(response|request|router|dispatcher)
- aura/web_kernel.(response|request|router|dispatcher)
- aura.web_kernel:(response|request|router|dispatcher)
- aura.web_kernel.(response|request|router|dispatcher)

... and so on. If you feel strongly about one of those variations, please speak up.

Thoughts on this or any other service naming convention?

* * *

That leaves us with the first problem, that of documenting what services are needed, which are defined, and which are modified by a package. A quick Google search does not reveal how Zend, Symfony, et al. are handling this, if at all.

One idea is to co-opt Composer again, and add an "extra:aura:services" element like so:

"extra": {
"aura": {
"services": {
"provides": {
"vendor/package:foo": "Vendor\Package\Foo",
"vendor/package:bar": "Vendor\Package\Bar"
},
"modifies": [
"other/package-baz:dib"
],
"requires": [
"another/package-zim:gir",
"and-yet/another:irk"
}
}
}
}

The "services" key is where we list the services.

The "provides" key lists the services provided by the package. It is a series of key-value pairs where the key is the service name, and the value is the class or interface exposed by the service.

The "modifies" key is a sequential array of services modified by the package. It does not specify a class name because we should probably not be changing the class or interface of the defined service. (The package may or may not use the modified services.)

The "requires" key is a sequential array of services from other packages that this package needs.

This seems pretty straightforward to me, and easy to work with, but there is at least one drawback. The composer.json definition is somewhat distant from the config/*.php files where the services are defined; if the configured services change, then you also need to change composer.json, and that can be a hassle.

One alternative would be to introduce an annotation for the config file docblocks, perhaps `@provides-service`, @modifies-service`, and `@requires-service`. That would keep the documentation closer to the actual configuration code, but it becomes somewhat harder to parse, and would probably require wider community involvement on standardizing the format.

Thoughts on these or or other service documentation ideas?

* * *

Thanks everyone!


--
Paul M. Jones
pmjo...@gmail.com
http://paul-m-jones.com

Modernizing Legacy Applications in PHP
http://mlaphp.com



Stan Lemon

unread,
Apr 20, 2014, 7:40:49 PM4/20/14
to aur...@googlegroups.com
Personally I’m not a big fan of names with slashes - I’d prefer something more akin to aura.web-kernel.router than what you proposed.  That’s just my $.02 though, it may not even be worth that much so don’t take it to the bank. ;)

As for things like ‘ web_dispatcher’ vs. ‘aura.web-kernel.dispatcher’ I’d suggest maybe considering declaring them fully-qualified and than adding the ability to alias a service to the shorter handle.  This is a convention some of the other frameworks are using, which allow the overriding of the alias in subsequent configuration without having to use long fully qualified service names.  For example, monolog has a bunch of services configured in sf2’s std edition but alias to just ‘logger’ so it can be referenced in that fashion. This is nice too when developing something that doesn’t necessary care about the specific service implementation.

I’ve got some experience with sf2 so I can explain a little how service definitions tend to work… In sf2 world more services are declared in a bundle’s service definition, which is normally an xml or yaml file.  By convention it’s in the same place in the directory tree, so when you want to see what and how a bundle uses it’s easy to pull up this xml/yaml file and see the full scope.  The only variance to this is that sf2 also allows for compiler passes which are programmatic ways to change the service definition when the kernel boot’s, but here too the files for this are located by convention and usually predictable to identify.

I would probably steer clear of annotations. They’re sexy, but PHP is already difficult enough to lint w/o primitive type hinting and the recurring theme with those frameworks embracing annotation configuration is that they really suck to debug when you’ve got a typo.  Furthermore if they’re not in the generally accepted list of annotations, such as the ones prescribed by phpdoc and phpunit than frameworks which require class mapping of annotations (ie. doctrine 2’s annotation library) need to explicitly configure said libraries not to freak the heck out. That’s not earth shattering, but it’s worth considering IMO.

A question if I may… have you seen any other frameworks/libraries/packages/components using the composer ‘extra’ section in the way aura does?  Just a question out of curiosity.

SL
--
You received this message because you are subscribed to the Google Groups "The Aura Project for PHP" group.
To unsubscribe from this group and stop receiving emails from it, send an email to auraphp+u...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Hari K T

unread,
Apr 21, 2014, 1:14:11 AM4/21/14
to aur...@googlegroups.com
Hey,

Thank you for bringing this. I will write inline.

Two issues have been at the back of my mind regarding service names, and now is the time to bring them up. These issues are related to each other.

First, it's hard to tell what services a package defines, and which ones it modifies. In order to find that out, you need to walk through the configuration `define()` code and examine it directly for `$di->set(...)` calls, and the then examine the `modify()` code for `$di->get()` code.

Second, we currently name shared services in a project container pretty loosely. We have a "logger", a "web_responder", "cli_dispatcher", and so on. This loose naming means it may be tough to combine services from different packages. If VendorFoo.Package creates a "zim" service and VendorBar.Package also creates a "zim" service then they will be in conflict.

I'd like to discuss our options related to these two issues.

* * *

I think the second problem is the easier one to solve. I propose that from here on we name services *for the package in which they are defined*. The service name should begin with the Composer-style package name, be followed by a colon, and then match ([A-Za-z][A-Za-z0-9_]*) in the name (so that the latter part can mimic variable name).

For example, the Aura.Web_Kernel package currently defines four services:

- `$di->set('web_request', ...)`
- `$di->set('web_response', ...)`
- `$di->set('web_router', ...)`
- `$di->set('web_dispatcher', ...)`

Under the new proposal for names, they would become:

- `$di->set('aura/web-kernel:request', ...)`
- `$di->set('aura/web-kernel:response', ...)`
- `$di->set('aura/web-kernel:router', ...)`
- `$di->set('aura/web-kernel:dispatcher', ...)`

FWIW, I tried several variations, and this is the one that looks least like a class name. Because project config files will have a mix of class name references and service name references, I want them to be easily distinguishable. The other variations included ...

- Aura\Web_Kernel\(Response|Request|Router|Dispatcher)
- Aura\Web_Kernel:(response|request|router|dispatcher)
- Aura\Web_Kernel.(response|request|router|dispatcher)
- Aura.Web_Kernel.(response|request|router|dispatcher)
- aura/web_kernel.(response|request|router|dispatcher)
- aura.web_kernel:(response|request|router|dispatcher)
 
- aura.web_kernel.(response|request|router|dispatcher)

I am with aura.web_kernel.(response|request|router|dispatcher) .

Additionally I would like to have things like Aura.Web_Kernel.(response|request|router|dispatcher) can be converted to small letters, or Aura\Web_Kernel\(Response|Request|Router|Dispatcher) to small letters rearranging back slash ( \ ) with dot ( . ) so all will be same as aura.web_kernel.(response|request|router|dispatcher) . The advantage I am seeing is people who are interested to have names as fully qualified class name can have the same variation.
 

... and so on. If you feel strongly about one of those variations, please speak up.

Thoughts on this or any other service naming convention?

* * *

That leaves us with the first problem, that of documenting what services are needed, which are defined, and which are modified by a package. A quick Google search does not reveal how Zend, Symfony, et al. are handling this, if at all.

One idea is to co-opt Composer again, and add an "extra:aura:services" element like so:

    "extra": {
        "aura": {
            "services": {
                "provides": {
                    "vendor/package:foo": "Vendor\Package\Foo",
                    "vendor/package:bar": "Vendor\Package\Bar"
                },
                "modifies": [
                    "other/package-baz:dib"
                ],
                "requires": [
                    "another/package-zim:gir",
                    "and-yet/another:irk"
                }
            }
        }
    }

The "services" key is where we list the services.

The "provides" key lists the services provided by the package. It is a series of key-value pairs where the key is the service name, and the value is the class or interface exposed by the service.

The "modifies" key is a sequential array of services modified by the package. It does not specify a class name because we should probably not be changing the class or interface of the defined service. (The package may or may not use the modified services.)

The "requires" key is a sequential array of services from other packages that this package needs.

This seems pretty straightforward to me, and easy to work with,

Are'nt you just trying to let people say these are the services and which can be used like just documenting in README.md ?
 
but there is at least one drawback. The composer.json definition is somewhat distant from the config/*.php files where the services are defined; if the configured services change, then you also need to change composer.json, and that can be a hassle.

If you remove a service or say a class method itself we should document in README.md , isn't the same for changing in composer.json ? ( I believe even if you don't remove it, there will not be much issues )
 

One alternative would be to introduce an annotation for the config file docblocks, perhaps `@provides-service`, @modifies-service`, and `@requires-service`. That would keep the documentation closer to the actual configuration code, but it becomes somewhat harder to parse, and would probably require wider community involvement on standardizing the format.

If it is just for documentation purpose annotation sounds good. We don't need to parse anything. But looking at your message I feel you are looking to parse the annotation and read from it. Then I am not in favour of it . Typos never give you good results / information. Else the parser should be so strong.
 

Thoughts on these or or other service documentation ideas?

* * *

Thanks everyone!

You are welcome :-) .
 
Hari K T

You can ring me : +91 9388 75 8821

Skype  : kthari85
Twitter : harikt
Message has been deleted

George Papadopoulos

unread,
Apr 21, 2014, 6:52:54 AM4/21/14
to aur...@googlegroups.com
Hi all!

For the second problem i'm in favor of the fully qualified name (as @mwop pointed out in twitter conversation). For the notation personally i'm using the backslash notation.

Eg in my projects i am using something like

    $di->set('Acme\Visitor\Repository\RepositoryInterface', function() { /* create a concrete Acme\Visitor\Repository\RepositoryInterface instance */ });

For the first problem, i prefer to read the source :-)

Stephan Hochdoerfer

unread,
Apr 21, 2014, 10:03:08 AM4/21/14
to aur...@googlegroups.com
Hi all,

first of all I do not know Aura in detail so my thoughts are based on my past experience with other DI implementations. If I completely miss I the point simply ignore what I just wrote ;)

Am Montag, 21. April 2014 01:11:17 UTC+2 schrieb pmjones:

First, it's hard to tell what services a package defines, and which ones it modifies. In order to find that out, you need to walk through the configuration `define()` code and examine it directly for `$di->set(...)` calls, and the then examine the `modify()` code for `$di->get()` code.

The overall problem mentioned is clearly one of the drawbacks of an external DI configuration (separate config file). If one would use interal DI configuration most of the issues might not come up as the wiring happens based on the existing type hints and maybe a few annotations here and there. I would simply pull in a dependency via Composer, add a type hint and everything works automatically. The classes I pulled in will be exposed by my IDE via auto-completion so there`s really nothing to do for me here.

However things are different when it comes to an external configuration. To be honest I do not see any good solution here. Ideally my IDE would also help me in this case, I mean auto-completion and the like for the configuration code. I did not realize that this is really useful until I had to use the Spring IDE for quite a while. Having auto-completion in the configuration code is really a big win. 

This is currently one of the biggest hurdles when it comes to DI adoption. For years I keep saying that we need a solution for this problem but with the tons of different configuration formats this is obviously not easy to achieve. DI needs to be a first class citizen of our IDEs.

 
Second, we currently name shared services in a project container pretty loosely. We have a "logger", a "web_responder", "cli_dispatcher", and so on. This loose naming means it may be tough to combine services from different packages. If VendorFoo.Package creates a "zim" service and VendorBar.Package also creates a "zim" service then they will be in conflict.


 Ah, naming conventions again. That problem seems not to die ;) I am not sure if it makes sense to use the namespace + classname as an unique identifier. You are duplicating information here which probably will hurt you when you try to move classes around. Renaming the identifiers later will probably hurt your users as they have to change their configuration after upgrading. If there is no work-a-round for that you would at least need to carefully state these changes in your "upgrade" docs to make the transition is as easy as possible for your users. It can really be painful to "debug" these issues by hand.

In our case we try to move away from using class names as identifiers. We try to use more generic terms, e.g. the identifier for our database connection dependency is named "DatabaseConnection" which reads nicely in the configuration ("I need to inject a database connection into my user repository"). Since we write applications for different databases I do not want to have that information in my configuration code, that does not matter here. And in case I would switch the RDBMs later I do not need to change the configuration code.

The downside of both the Composer approach and the annotation approach is information duplication. You always need to make sure that your configuration code is in sync with your metadata. If you let me choose between the two I would probably go for the annotation based approach. But again if your IDE does not display the information in any way it might be useless. I have to either read the docblock of the class or search in the configuration code for the class name. Not sure if that really helps the user.

I would say that for your users it does not matter which class resides in which package, they can easily find the implementation when searching for the class name in their IDE.

And now to the good part of external configuration: If you figure out that there is a naming clash somewhere you can easily create your own configuration code to solve the problem.

Stephan Hochdörfer

Paul M. Jones

unread,
Aug 9, 2014, 1:21:56 PM8/9/14
to aur...@googlegroups.com
Hi all!

Coming back to this topic after a hiatus; the intervening time has been filled with book writing, conferences, the ADR paper, and other work. However, as we approach completion of the *_Kernel and *_Project dependencies, this takes on renewed importance.

To refresh your memory, the main element here is how to name services provided by Aura and Aura-compliant packages. I proposed a naming standard that uses the Composer package name in which the service is defined, along with a specific service name within that package. So, an Aura-compliant package with the Composer name `foo/bar` could provide services named `foo/bar:baz` or `foo/bar:dib_zim`.

The benefit here is deconflict service names between packages so that no `baz` service ever overwrites another, and so that we can tell from the service name where it is defined in the first place. This also allows *_Bundle packages to define services that are based on classes in other packages, but that was not specified in the original message.

Here are the summarized comments so far.

* * *

### Hari KT

Hari prefers service names to be snake-case with dots, instead of the original proposal:

> I am with aura.web_kernel.(response|request|router|dispatcher)

I don't see any particular problems with this; it was one of the variations I tried (although I still like the above proposal better).

> Additionally I would like to have things like Aura.Web_Kernel.(response|request|router|dispatcher) can be converted to small letters, or Aura\Web_Kernel\(Response|Request|Router|Dispatcher) to small letters rearranging back slash ( \ ) with dot ( . ) so all will be same as aura.web_kernel.(response|request|router|dispatcher) . The advantage I am seeing is people who are interested to have names as fully qualified class name can have the same variation.

While I get that it's nice to allow different projects to use their own conventions, I'd rather see a single standard, instead of a mix of "allowed combinations" that then get transformed under-the-hood.

### George Papadopoulos

George prefers service names that look like fully-qualified class names:

> i'm in favor of the fully qualified name (as @mwop pointed out in twitter conversation). For the notation personally i'm using the backslash notation.
>
> $di->set('Acme\Visitor\Repository\RepositoryInterface', ...);

Jake Smith, in other correspondence, also likes this kind of service naming, because it allows him to match a specific class name to a service for that class name.

I see various problems with this (although I'll admit they are predictive and not historical). For example, this looks an awful lot like a class name to name and not a service name; when scanning the code by eye, it'd be easier to confuse the service name with the class name. That might not actually be a problem if that's your intent, though. A second example comes when you end up with, or need, two different services based on the same class name, such as two Aura\Sql\ExtendedPdo connection objects.

### Stephan Hochdörfer

Stephan has some meta-commentary:

> I am not sure if it makes sense to use the namespace + classname as an unique identifier. You are duplicating information here which probably will hurt you when you try to move classes around.
>
> ...
>
> In our case we try to move away from using class names as identifiers.

(Be sure to read his full commentary.)

This strikes me as not necessarily in favor of the original proposal, but as a historical record of the problems I talked about in reference to fully-qualified class names above.

> I would say that for your users it does not matter which class resides in which package

To be clear, I'm talking about the names of *services* and not the names of classes here. An object instance provided as a service might (should?) be named for something other than its class name, although the class name is likely to indicate what kind of service it is. For example, I argue against `Aura\Web\Request` as a service name, but `aura.web.request` or `aura/web:request` would be reasonable.

* * *

So there doesn't seem to be much public consensus at this point. Any other thoughts on this topic?

Paul M. Jones

unread,
Aug 9, 2014, 1:28:07 PM8/9/14
to aur...@googlegroups.com

On Aug 9, 2014, at 12:21 PM, Paul M. Jones <pmjo...@gmail.com> wrote:

> Here are the summarized comments so far.

I failed to include Stan Lemon's comments.

* * *

### Stan Lemon

Stan, like Hari, prefers the the snake-case dotted notation:

> Personally I’m not a big fan of names with slashes - I’d prefer something more akin to aura.web-kernel.router than what you proposed.

Then we have this:

> As for things like ‘web_dispatcher’ vs. ‘aura.web-kernel.dispatcher’ I’d suggest maybe considering declaring them fully-qualified and than adding the ability to alias a service to the shorter handle.

Anything that sounds like "fully qualifed" in a service name seems like it carries the problems I and Stephan Hochdörfer mention regarding class names.
> --
> You received this message because you are subscribed to the Google Groups "The Aura Project for PHP" group.
> To unsubscribe from this group and stop receiving emails from it, send an email to auraphp+u...@googlegroups.com.
> For more options, visit https://groups.google.com/d/optout.

Hari K T

unread,
Aug 15, 2014, 10:46:02 PM8/15/14
to aur...@googlegroups.com
Hey Paul,

So finally what is your plan on this?

Hari K T

You can ring me : +91 9388 75 8821

Skype  : kthari85
Twitter : harikt


Stephan Hochdörfer

unread,
Aug 17, 2014, 2:22:06 PM8/17/14
to aur...@googlegroups.com
Am Samstag, 9. August 2014 19:21:56 UTC+2 schrieb pmjones:

To be clear, I'm talking about the names of *services* and not the names of classes here.  An object instance provided as a service might (should?) be named for something other than its class name, although the class name is likely to indicate what kind of service it is.  For example, I argue against `Aura\Web\Request` as a service name, but `aura.web.request` or `aura/web:request` would be reasonable.


Ok, I was assuming your are talking about class names, not service names. Since we are talking about loosely coupled components, am I fine to assume that "Request" is a pretty unique name for a service and for that should be easy to "identify" by a developer? I mean I fully get your idea behind the naming scheme but am I not sure if it is really needed.

Anyway if you let me decide between `aura.web.request` or `aura/web:request` I`d go for `aura.web.request`. The latter one looks really wired to me.

Stephan Hochdörfer

Jesse Burns

unread,
Aug 18, 2014, 4:50:14 AM8/18/14
to aur...@googlegroups.com
I know I've been quiet around here, but my preference is the following
format:

aura/web-kernel.(response|request|router|dispatcher)


> - `$di->set('aura/web-kernel:request', ...)`
> - `$di->set('aura/web-kernel:response', ...)`
> - `$di->set('aura/web-kernel:router', ...)`
> - `$di->set('aura/web-kernel:dispatcher', ...)`

Using the slash/dashed/colon format looks pleasing to my eye, as it's an
instant visual indicator that this element (a service belonging to a
specific package) is different from a class/method or anything else in
the PSR recommendations.

I think it compliments PSR-1/PSR-2 in a very clean way, while also
visually relating the service to it's package's Composer naming scheme.

That's my two cents ;-)

--

Jesse Burns
jbWebWare.com - Bringing The Web To You!!!
AllianceCMS.com - Bringing Us Together!!!


Hari K T

unread,
Aug 18, 2014, 4:56:32 AM8/18/14
to aur...@googlegroups.com
I know I've been quiet around here, but my preference is the following format:

aura/web-kernel.(response|request|router|dispatcher)

I don't disagree with this either :) .

Looking at this quite for some time I am also into this team ;) .

Paul M. Jones

unread,
Aug 18, 2014, 12:09:34 PM8/18/14
to aur...@googlegroups.com
On Aug 18, 2014, at 3:50 AM, Jesse Burns <jbur...@gmail.com> wrote:

> Using the slash/dashed/colon format looks pleasing to my eye, as it's an instant visual indicator that this element (a service belonging to a specific package) is different from a class/method or anything else in the PSR recommendations.

On Aug 18, 2014, at 3:56 AM, Hari K T <ktha...@gmail.com> wrote:

> Looking at this quite for some time I am also into this team ;) .

So it seems like the current consensus is for "vendor/package:service".

Any other thoughts? If not I can start changing the existing v2 configs to start using this.

Hari K T

unread,
Aug 19, 2014, 8:53:07 AM8/19/14
to aur...@googlegroups.com
Since we are talking about loosely coupled components, am I fine to assume that "Request" is a pretty unique name for a service and for that should be easy to "identify" by a developer? I mean I fully get your idea behind the naming scheme but am I not sure if it is really needed.

I fear there can be overlap in names.
 
Anyway if you let me decide between `aura.web.request` or `aura/web:request` I`d go for `aura.web.request`. The latter one looks really wired to me.

First I do was having the same feeling. But later I felt it will be good to identify the package easily.

Looking for quite sometime it seems ok to me. I am sure once we are into it we will not be having any trouble. Recalling the old war on namespace \ . ;) .

Thank you
Reply all
Reply to author
Forward
0 new messages