I'm taking this discussion to the list, because it's much better for
discussion. Here's the original text from the ticket, with my
comments interspersed as necessary:
> I am a newcomer to puppet. This is bad as I don't know all the nuts
and bolts of the framework. But it is good as well as I still have a
"fresh view" of puppet as a tool. So please forgive me if I am telling
nonsense ... Anyhow I'd like to share some "fresh-view" conceptual
thoughts with you.
>
> I am really having conceptual (and practical!!) trouble with the
semantics of puppet's "classes" and "definitions" as they are defined
today. IMO the distinction is quite arbitrary and counter-intuitive.
Just so you know, this has come up multiple times, and I remain
convinced they have separate purposes.
Also, to be clear, I *wholly* encourage this kind of discussion and
recommendation. I've never claimed I have the ultimate vision of
Puppet's language, and I'm always looking for recommendations to make
it better. Of course, I will always defend the existing syntax, and I
will always fight to keep the basic vision I have intact.
The goal of a definition is to function as a composite resource,
allowing multiple Puppet resources to look like a single resource.
This makes it easy to do things like have an exec look like an
iptables rule, for instance. The key to definitions is that they
allow you to create new resource types that can be used with the exact
same syntax as builtin resources.
The point behind classes, however, is to delineate all of the
resources necessary to provide a given service. I often call them
'service classes', rather than just 'classes'.
Given this, there are really two questions:
1) Are these actually two separate purposes?
2) Have I chosen syntax that does a good job of meeting each purpose?
I maintain these are two clearly separate purposes.
However, I tend to think that the syntaxes aren't necessarily that
great, and I definitely agree that we need more functionality for
configurating classes while at the same time the functionality we have
is a bit not-so-great.
> AFAICS there are three main distinctions between classes and
definitions:
>
> 1) classes are singletons from a node perspective, definitions are
instantiable
> 2) definitions receive parameters, classes do not
> 3) classes can declare "class variables" ($class::var), definitions
cannot
These are more syntactical and structural distinctions, but to me, the
distinctions that matter are how they are and should be used.
> I have seen many examples in "recipes" where classes were used like
this:
>
> node abc {
> $globalvar1 = ...
> $globalvar2 = ... }
>
> include xyz
>
> class xyz {
> ...template("consumes <%= globalvar1 %>...")... }
>
> file { ...owner = $globalvar2... }
>
> IMO this is counter to basic principles of information hiding and
modularization. (The most exhaustive discussion of the disadvantages
of such an approach is probably in Steve McConnell's "Code Complete").
If you do not have the most simple classes in your manifests then
puppet invites you to use global variables. I can already see from the
few things I did that this quickly becomes a maintenance nightmare and
makes puppet classes very difficult to use in a more complex setting.
I agree, and I've been trying to find a better syntax for this. I
don't think the answer is to just use definitions, though.
> Definitions accept construction parameters and are therefore able
to hide their inner workings and complexity from outer context. This
makes them more flexible and attractive for modularization than
classes. Definitions are however not meant for usage as node
singletons. IMO it's always bad if you try to coerce a syntactical
construct into a role that it wasn't meant for. Defintions also have
another big disadvantage: They do not allow for instance variables
like classes do (something like $mydefinition["xyz"]::myvar).
>
> Furtheron the distinction between "classes as singletons" and
"definitions as prototypes" seems quite arbitrary to me. What is
called a "class" in puppet is conceptually a class with "automatic
instantiation" (with one "class instance" per node). This is confusing
to me as an OO programmers who considers classes and instances
separate conceptual entities. On the other hand what is called a
"definition" in puppet is conceptually really a class as it defines a
"blueprint" of an object that can be instantiated separately. The
conceptual inconsistency reveals itself in the Class["classname"]
syntax which is a workaround for the fact that puppet classes are
instances of classes as well. Definitions on the other hand can be
referenced quite intuitively with the Definition_name["instance id"]
syntax.
Part of the problem is that Puppet's language isn't a real
"programming" language, but I (possibly foolishly) chose many terms
that mean somewhat different things in other languages. Part of the
reason I did this is I was reusing language in tools like cfengine.
But the point remains: A Puppet class is more of a service class
than something like an OO class; it can also be thought of as the code
that specifies a class of machines -- that is, if you've got a
sendmail-class server, then you get sendmail-related resources.
> IMO the conceptual distinction between classes and definitions is
confusing and unnecessary at the same time. To me it would be much
simpler if such a distinction did not exist. Rather than two resource
containers you could simply have one generic class container without
loosing any functionality and winning flexibility, intuitivity and
maintainability:
>
> Here my propositions:
> 1) Classes should be reframed as universal "blueprints" of resource
containers that can (and must) be instantiated (like definitions today).
How would you instantiate a class?
> 2) All classes may define constructor parameters (like definitions
today).
This seems reasonable and desirable.
> 3) Classes may be defined as node level "singletons" or node level
"prototypes". The distinction between singleton and prototype is well
known to most OO programmers.
How would this distinction be made?
> 4) Classes can define public instance variables that may be
accessed from an outer context (like they do today). The access syntax
would be ($Classname["instance id"]::myvar).
Ugh. Not so fond of this. Really, I'd like to get rid of the
existing syntax, I just knew that something like it was necessary
until we had a better way of providing good encapsulation and
configuration for classes.
And what about singleton classes? Would you support classes without
instance names, and if so, what would that syntax look like?
> 5) Instances of classes can be referenced like definitions today:
Classname["instance id"]
This is just an automatic result of other bits above.
> All this can be introduced in a fully backwards compatible way
(which is certainly a must-have!):
> 1) Definitions will continue to exist but will be deprecated.
Don't definitions provide most of the functionality you want in your
classes? Wouldn't it make more sense to use them as the new 'class'
construct?
> 2) Classes will be node singletons by default.
> 3) Class constructor parameter declaration is optional.
> 4) Singleton classes can still be referenced as Class["xyz"]. This
usage will however be deprecated.
> 5) Class variables can still be referenced as $classname::var. This
usage will however be deprecated.
What about singleton classes classes that don't have multiple instances?
> 6) You can define "inner classes" to replace today's construct of
definitions within class context.
So today's definitions could only ever be defined inside other classes?
> Here is how I'd define the syntax of the ideal resource container
(replacing both classes and definitions), not really BNF but
somehow ;-) :
>
> {singleton|prototype} class <classname> [($par1, [$par2, [...]])] {
> ...
> $instance-var = ...
> ... {singleton|prototype} class <inner class> [($par1, [$par2,
[...]])] { ... }
> }
I can't figure out what you mean here. Can you show me some example
classes?
> The whole thing certainly is not very well thought out yet. But I'd
love to see a discussion starting from here as I am really fighting
with the current syntax...
>
--
Wear the old coat and buy the new book. -- Austin Phelps
---------------------------------------------------------------------
Luke Kanies | http://reductivelabs.com | http://madstop.com
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"Puppet Developers" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at
http://groups.google.com/group/puppet-dev?hl=en
-~----------~----~----~----~------~----~------~--~---