Skip to content

Extract API from Implementation #6129

@webmozart

Description

@webmozart

Hi everyone,

We had this discussion before, but at a point when we didn't have composer yet. I would like to bring this topic up again now.

Problem (updated December 5, 2012)

I just had a longer discussion with @fago, who is currently integrating the Validator component into Drupal. For Drupal it is necessary to replace the translation mechanism used in the Validator component by a custom implementation. Even when implementing Symfony\Component\Translation\TranslatorInterface in their code, this still pulls in all of the Symfony Translation implementation (and its potential dependencies).

The same is true for any Symfony component/bundle/bridge. When someone wants to use A which relies on B's interfaces, and B relies on C and D, he needs to pull in A, B, C and D and provide a custom implementation for B (that might depend on E and F). Lots of installed dependencies: A, B, C, D, Bcustom, E, F

         A
      .·´ `·.
     B     Bcustom
   .´`.     .´`.
  C    D   E    F
Proposal (updated January 7, 2013)

I would like to suggest and discuss a backwards compatible extraction of the Symfony API. In a nutshell, make it possible to use A which relies on B's interfaces but replace B with a custom implementation (i.e. only install A, Bcustom, E, F).

      A
      |
   Bcustom
    .´`.
   E    F
Implementation
api/
    Symfony/
        Component/
            Translation/
                TranslatorInterface.php
    composer.json [symfony/api]
src/
    Symfony/
        Component/
            Translation/
                Translator.php
                composer.json [symfony/translation, requires symfony/api, provides symfony/translation-implementation]
            Validator/
                composer.json [symfony/validator, requires symfony/api, suggests symfony/translation-implementation]
Example: Replacing the translator
Drupal/
    Translation/
        composer.json [drupal/translation, requires symfony/api, provides symfony/translation-implementation]

The package MUST NOT add symfony/translation to its "replace" section. Multiple implementations of the same interface are NOT mutually exclusive and CAN be used at the same time.

Example: Using the Validator with its simplistic default translator
{
    "require": {
        "symfony/validator": "2.2.*"
    }
}
Example: Using the Validator with the Symfony Translation component
{
    "require": {
        "symfony/validator": "2.2.*",
        "symfony/translation": "2.2.*"
    }
}
Example: Using the Validator with a custom implementation
{
    "require": {
        "symfony/validator": "2.2.*",
        "drupal/translation": "..."
    }
}

The API would comprise a closed set of interfaces and classes of the components, that is:

  • the top-level interface(s)
  • the classes and interfaces that the top-level interface(s) refer to in type hints and @return tags
  • the classes and interfaces that these classes and interfaces refer to
  • etc.

Because of composer, this change would be fully BC.

Benefits (updated December 5, 2012)
  1. A Symfony component A can rely on interfaces of another component B without forcing the user to use B.
  2. Other projects can depend on Symfony's interfaces with a lower barrier to entry.
  3. The API clearly documents the stable part of the components (it is ideally guaranteed not to change)
  4. The separation helps us to decouple our components more. For example, if a component A instantiates a class of another component B and thus requires "symfony/b", we can improve it to make use of DI so that it only depends on "symfony/api" instead.
Drawbacks (updated January 8, 2013)
  1. One more composer package (symfony/api) has to be downloaded when using a Symfony component.
  2. Core developers have to maintain interfaces in a separate directory.

Please let me know what you think.

Metadata

Metadata

Assignees

No one assigned

    Labels

    FormRFCRFC = Request For Comments (proposals about features that you want to be discussed)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions