Tuesday, May 28, 2013

Basic Designs for TYPO3.Boilerplate

I'm designing TYPO3.Boilerplate.

Basics of TYPO3.Boilerplate

  • Boilerplate Package[s] (Alternative name: Boilerplate[s]): A package that resides in FlowRoot/Packages/Boilerplates/ which has stuff that may be integrated into another package.
  • Derivative Package[s] (Alternative name: Derivative[s] or Boilerplate Derivative[s]): A package that integrates one or more boilerplate packages.
  • Naked Boilerplate[s]: The raw materials that makes a boilerplate without the metadata that TYPO3.Boilerplate needs to create Derivative Packages. These are often part of other packages or libraries. A site package might store the designer provided HTML/CSS files somewhere in the Resources.
TYPO3.Boilerplate is not very useful (from a user's perspective) on it's own, but is powerful within a Builder app such as FluidBuilder or PackageBuilder.

Boilerplates and Derivatives

TYPO3.Boilerplate is concerned with copying stuff from a Boilerplate package to a Derivative Package including interfaces to help Builders process or manipulate the files that get copied. Though the builders work with files, they should be able to treat them as objects via TYPO3.Boilerplate APIs.

Though I could say that Boilerplates and Derivatives have a parent-child relationship, I thought that would suggest a much more dependent or a hierarchical relationship. Derivative Packages should have a copy of everything they need from the Boilerplate. These Derivatives should never depend on Boilerplates. Only Builders that use a particular Boilerplate package should depend on the Boilerplates.

Are there situations where something other than a Builder (or a Kickstarter) can depend on a Boilerplate? One possible situation would be an agency (or maybe even Neos) that has a collection of widgets that they store in a Boilerplate package, and reuse those widgets, without modification, in their site packages. In that case, I suppose they could introduce a dependency in their composer.json, but then they run the risk of upgrading one little thing in their boilerplate only to break things in the dependent site packages. It would be better to copy the widgets into the site packages, and then have a Boilerplate Migration that helps to update site packages from one Boilerplate version to the next. In any case, I don't think there should a technical limitation that prevents the dependency; It'd be one of those only-do-this-if-you-know-what-you're-doing kind of things.

I wonder if TYPO3.Neos.NodeTypes could be considered a Boilerplate package.

Please respond in the comments, or in the Neos forum, and let me know what you think of this design direction.

Naked Boilerplates and Boilerplate Metadata

In initial designs, I used the term Virtual Boilerplate, but I think Naked Boilerplate is a more appropriate term, because it has templates, but they are missing any boilerplate metadata. It is up to a Builder Package whether or not they support Naked Boilerplates. For some Builders, like PackageBuilder, it won't make much sense. For others, like FluidBuilder (TemplateBuilder?), it makes a lot of sense to support templates that have not been converted into Fluid templates already.

These HTML/CSS/JS templates that have not been broken into Fluid templates are Naked Boilerplates. For example, Twitter Bootstrap is a Naked Boilerplate. To create a Fluid Boilerplate Package, Twitter Bootstrap gets integrated into some Fluid templates with metadata that tells TYPO3.Boilerplate
  • which Builder to use (FluidBuilder) and
  • what stuff is available in the Boilerplate (lists of layouts, widgets, options like changing colors, etc)
The Builder uses that metadata to present a list of stuff to the user. They can then integrate that stuff into their own Derivative Package. FluidBuilder could create fluid templates in an Application package or a Site package using the widgets/options (stuff) that the user chooses from the list of available stuff.

The site package that is based on Twitter Bootstrap does not have information about all of the widgets available in the Boilerplate package; Instead, it contains metadata about which parts of the Boilerplates were integrated into it (e.g. which widgets were included in the site or application package). Ideally, the Derivative Package could have enough information to facilitate upgrades from one Boilerplate version to the next (deltas or diffs or steps taken to create the site package from the old boilerplate. These changes would be rebased--like git--on the new version to help with template upgrades).

Derivative Metadata

Derivative Packages will need metadata about:
  • Integrated Boilerplates
    • Which Boilerplates have been integrated
    • What stuff (layouts/widgets/components) came from a particular Boilerplate (I assume that if it didn't come from the Boilerplate, then it was added by the developer, so care should be taken not to overwrite those changes.)
    • How things were integrated (like where widgets were inserted) could use Eel/FlowQuery (my preference) or XPath (which only works on XML-like files, but could be very useful in some cases.)
  • Versioning Information to facilitate Migrations
    • Kickstarters and Builders might not support migrating from one version of a Boilerplate to the next, but they should store something that says which version of a Boilerplate was used in generating the derivative package.
    • Neos and other agencies might provide a Boilerplate package with a collection of widgets that can be added to templates. How/where these widgets are inserted should be carefully recorded, so that changes may be replayed/rebased on any manual template modifications or to facilitate migrating a package from one boilerplate version to the next.
  • Builder-specific options
    • For example, the FluidBuilder (maybe TemplateBuilder would be a better name) would have a theme layer that uses theming options. If a Boilerplate can be customized with custom colors (think SASS or LESS), then the Builder could expose those options in some kind of interface.

Initial Thoughts on Code

Note: I need to go through Flow's code again to decide which parts can be reused. Possibilities include:

  • Configuration (Store all the metadata in yaml files)
  • Monitor (File Monitor / Change Detection, Possibly implement ChangeDetectionStrategyInterface to look for specific changes in target files)
  • Package (This has some cool stuff, but I can't depend on a package being "activated" before I interact with it, since Builders and Kickstarters will be creating packages. Packages might be broken until a Kickstarter/Builder is finished creating it.) 
  • Reflection (Possibly only useful in builders that work with PHP...)
  • Resource (Could be very helpful, as long as it's not restricted to just the Resources Folder. This needs to be able to interact with any file in a package)
  • Utilities (File manipulation stuff)
For the services and the domain (which does not get persisted to a database, everything is stored in files), we have:
  • Model
    • Packages/ (Builders should extend these to provide the business-logic of how to manipulate relevant parts of a Derivative based on metadata from the Boilerplate)
      • AbstractPackage implements PackageInterface
      • BoilerplatePackage extends AbstractPackage
      • DerivativePackage extends AbstractPackage (might be a Site or Applicaiton)
      • (Others like library could be implemented at some point if someone needs it, but they might not extend the PackageInterface... I'm not sure on that, and I think it is outside the scope of this project.)
    • NakedBoilerplateInterface
  • Factories (extended in Builder packages to provide implementation details of how to work with different parts of a package)
    • Copy between packages (Boilerplate to Site; Boilerplate to Application)
  • Repository (Each package type has a separate repository that extends the basic repository)
    • BoilerplateRepository is the collection of BoilerplatePackages
    • SitePackagesRepository is a collection of DerivativePackages
    • ApplicationRepository is a collection of DerivativePackages
  • Service
    • RoundTrip service (like PackageBuilder: Detecting changes in watched packages to trigger updates in registered Builders -- Uses FileMonitor)
    • Migration service (assists in migrating a Derivative from one Boilerplate version to the next, assuming the boilerplate included migration scripts. For inspiration: Doctrine Migrations, TYPO3CR Migrations, Flow Code Migrations, git rebase and friends)

Boilerplate Math

Calculus is my inspiration for and explanation of how TYPO3.Boilerplate works. I call this, Boilerplate Math.

NOTE: I don't think people need to understand that I got the terms from Calculus to use the Boilerplate API. "Integrate" and "derive" are common enough words, that I think the meaning will be easy enough to understood for anyone who needs to use the Boilerplate API. But, for those that might want to modify Boilerplate, the history of them might come in handy.

Consider these basic calculus equations:
Integrate f'(x) to get f(x) plus some change

Derive f'(x) from f(x) plus some change

If I say that f'(x) is a Fluid Boilerplate package that gets integrated into f(x), a SitePackage, then:
Integrate Fluid (f) Boilerplate (B) into SitePackage (P) with Changeset (C)

Derive Fluid (f) Boilerplate (B) Package (p) from SitePackage (P) with Chagneset (C)  
A SitePackage might use parts from more than one Fluid Boilerplate. For example, it could integrate some widgets from twitter bootstrap as well as widgets from an agency's custom boilerplate that they use for many of their websites.