Issue #1645 has been updated by Luke Kanies.

Assignee changed from Luke Kanies to Nigel Kersten


----------------------------------------
Feature #1645: Classes vs. Definitions - how to get closer to common design 
patterns
https://projects.puppetlabs.com/issues/1645

Author: Florian Grandel
Status: Needs design decision
Priority: Normal
Assignee: Nigel Kersten
Category: language
Target version: unplanned
Affected Puppet version: 0.24.4
Keywords: 
Branch: 


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. 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

I have seen many examples in "recipes" where classes were used like this:
<pre>
node abc {
  $globalvar1 = ...
  $globalvar2 = ...

  include xyz
}

class xyz {
   ...template("consumes <%= globalvar1 %>...")...

   file { ...owner = $globalvar2... }
}
</pre>
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.

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.

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).
2) All classes may define constructor parameters (like definitions today).
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.
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).
5) Instances of classes can be referenced like definitions today: 
Classname["instance id"]

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.
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.
6) You can define "inner classes" to replace today's construct of definitions 
within class context.

Here is how I'd define the syntax of the ideal resource container (replacing 
both classes and definitions), not really BNF but somehow ;-) :
<pre>
{singleton|prototype} class <classname> [($par1, [$par2, [...]])] {
    ...
    $instance-var = ...
    ...
    {singleton|prototype} class <inner class> [($par1, [$par2, [...]])] { ... }
}
</pre>
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...


-- 
You have received this notification because you have either subscribed to it, 
or are involved in it.
To change your notification preferences, please click here: 
http://projects.puppetlabs.com/my/account

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Bugs" 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-bugs?hl=en.

Reply via email to