7156248 rad best practices: naming
authorGary Pennington <gary.pennington@oracle.com>
Fri, 23 Mar 2012 12:21:59 -0700
changeset 819 d2f77a136379
parent 818 59c0ea842635
child 820 654f8c0ddf84
7156248 rad best practices: naming
usr/src/doc/rad-dev/c-best-practices.xml
usr/src/doc/rad-dev/c-concepts-design.xml
usr/src/doc/rad-dev/c-concepts.xml
--- a/usr/src/doc/rad-dev/c-best-practices.xml	Fri Mar 23 12:47:27 2012 -0400
+++ b/usr/src/doc/rad-dev/c-best-practices.xml	Fri Mar 23 12:21:59 2012 -0700
@@ -19,6 +19,288 @@
 <chapter>
   <title>RAD Best Practices</title>
 
+    <para>
+        This chapter provides guidance when using RAD. The guidance
+        material is grouped around the following topics.
+    </para>
+    <para>
+        <itemizedlist>
+            <listitem>
+                <para>
+                    When to use RAD
+                </para>
+            </listitem>
+            <listitem>
+                <para>
+                    How to use RAD
+                </para>
+            </listitem>
+        </itemizedlist>
+    </para>
+    <section id="best-practices.when">
+        <title>When To Use RAD</title>
+        <para>
+            RAD is designed to provide remote administrative interfaces
+            for operating system components/sub-systems. Such interfaces
+            support the distributed administration of systems and greatly
+            increase the abilities of system administrators to support
+            large installations.
+        </para>
+        <para>
+            It is not intended to be a general purpose mechanism for
+            building distributed applications, many alternative
+            facilities (e.g.: RPC, RMI, CORBA, MPI, ...) exist for
+            such applications.
+        </para>
+    </section>
+    <section id="best-practices.how">
+        <title>How To Use RAD</title>
+        <para>
+            This section contains specific guidance on how to use RAD.
+        </para>
+        <section id="best-practices.how.interface">
+            <title>Interface Guidelines</title>
+            <para>
+                Designing a RAD interface requires judgement and the
+                application of domain knowledge.
+            </para>
+            <section id="best-practices.how.who">
+                <title>Target Audience</title>
+                <para>
+                    The users of the interface represent the primary
+                    goal driving the design. There are two broad
+                    categories of consumers:
+                    <itemizedlist>
+                        <listitem>
+                            <para>
+                                Administrators
+                            </para>
+                        </listitem>
+                        <listitem>
+                            <para>
+                                Developers
+                            </para>
+                        </listitem>
+                    </itemizedlist>
+                </para>
+                <para>
+                    Unfortunately, it's rarely possible to accomodate
+                    the desires of these two categories easily within
+                    one interface. The first group desire "task-based" APIs
+                    which match directly onto well-understood and
+                    defined administrative activities. The second
+                    group desire detailed, "operation-based" interfaces which
+                    may be aggregated to better support unusual or
+                    niche administrative activities.
+                </para>
+                <para>
+                    For any given sub-system, you can view existing
+                    command line utilities (CLIs) and libraries (APIs)
+                    as expressions of the RAD APIs which are
+                    required. The CLIs represent the "task-based"
+                    administrative interfaces and the APIs represent
+                    the "operation-based" developer interfaces.
+                </para>
+                <para>
+                    The goal in using RAD is to provide interfaces
+                    that address the lowest-level objectives of the
+                    target audience.  If targeting administrators
+                    (task-based), this could translate to matching
+                    existing CLIs.  If targeting developers, this
+                    could mean significantly less aggregation of
+                    the lower-level APIs.
+                </para>
+            </section>
+            <section id="best-practices.how.constraints">
+                <title>Legacy Constraints</title>
+                <para>
+                    Many sub-systems present incomplete interfaces to
+                    the world. There are CLIs which contain processing
+                    capabilities that are not accessible from an
+                    existing API (This is another motivation for
+                    providing "task-based" administrative interfaces before
+                    introducing more detailed interfaces.).
+                </para>
+                <para>
+                    Such constraints must be considered in the RAD API
+                    design. It is valid to consider migrating
+                    functionionality from the CLI into the API to
+                    facilitate the creation of the new interface. It
+                    is also valid to consider presenting an interface
+                    which wraps the CLI and takes advantage of the
+                    existing functionality. It is not valid to simply
+                    duplicate the functionality in the new RAD
+                    interface. This would introduce redundancy and
+                    significantly increase maintenance complexity. One
+                    particular area where RAD interface developers
+                    need to be careful is to avoid duplication around
+                    parameter checking and transformation. This is
+                    likely to be a sign that existing CLI
+                    functionality should be migrated to an API.
+                </para>
+                <para>
+                    RAD modules must be written in C. For some
+                    sub-systems, for instance those written in other
+                    languages, there is no mechanism for a C module to
+                    access API functionalty. In these cases RAD module
+                    creators have little choice but to access whatever
+                    functionality is available in the CLI or to
+                    undertake potentially significant engineering
+                    effort to access the existing functionality
+                    (re-write existing code in C, embed a language
+                    interpreter in their C module, ...).
+                </para>
+            </section>
+            <section id="best-practices.how.conservative">
+                <title>Conservative Design</title>
+                <para>
+                    Desiging a RAD interface is very similar to
+                    designing a library interface. The same general
+                    principles of design apply: be conservative, start
+                    small, consider evoloutionary paths, carefully
+                    consider committment levels.
+                </para>
+                <para>
+                    Once an interface is established, the use of
+                    versioning and considered, incremental
+                    improvements will flesh out the functionality.
+                </para>
+            </section>
+        </section>
+        <section id="best-practices.how.component">
+            <title>Component Guidelines</title>
+            <para>
+                This section presents specific design advice on the
+                most significant components of a RAD module. Naming is
+                addressed separately in the naming section of this
+                chapter.
+            </para>
+            <section id="best-practices.how.component.api">
+                <title>API</title>
+                <para>
+                    APIs represent the primary deliverable of a RAD
+                    module. They represent a grouping of interfaces,
+                    events, methods and properties which allow a user
+                    to interact with a sub-system.
+                </para>
+                <para>
+                    When exposing the elements of a sub-system
+                    consider carefully how existing functions can be
+                    grouped together to form an interface. Imperative
+                    languages, such as C, tend to pass structures as
+                    the first argument to functions. This provides a
+                    clear indicator as to how best to group functions
+                    into APIs.
+                </para>
+            </section>
+            <section id="best-practices.how.component.method">
+                <title>Method</title>
+                <para>
+                    Methods provide mechanisms for examining and
+                    modifying administrative state.
+                </para>
+                <para>
+                    Consider grouping together existing native APIs
+                    into aggregated RAD functions which allow higher
+                    order operations to be exposed.
+                </para>
+                <para>
+                    Follow established good practice for RPC style
+                    development. RAD is primarily for remote
+                    administration and avoiding excessive network load
+                    is good practice.
+                </para>
+            </section>
+            <section id="best-practices.how.component.property">
+                <title>Property</title>
+                <para>
+                    Do define an &lt;error&gt; element with properties
+                    which can be modified.
+                </para>
+            </section>
+            <section id="best-practices.how.component.event">
+                <title>Event</title>
+                <para>
+                    The module is responsible for providing a sequence
+                    number and it's at the discretion of the module
+                    author to decide how this is done. Monotonically
+                    increasing sequence numbers are recommended for
+                    use, since these will be of most potential use to
+                    any clients.
+                </para>
+                <para>
+                    Consider providing mechanisms for allowing a
+                    client to throttle event generation.
+                </para>
+                <para>
+                    Carefully design event payloads to minimize
+                    network load.
+                </para>
+                <para>
+                    Don't try to replicate the functionality of
+                    network monitoring protocols such as SNMP.
+                </para>
+            </section>
+            <section id="best-practices.how.component.proxy">
+                <title>Module location: proxy or slave</title>
+                <para>
+                    Judicious use of the is_proxy variable allows a
+                    module implementor to control where a module is
+                    loaded for execution: in the RAD proxy or a slave
+                    process.
+                </para>
+                <para>
+                    A module should, by default, be designed to be
+                    loaded into a slave process unless the following
+                    conditions apply:
+                </para>
+                <para>
+                    <itemizedlist>
+                        <listitem>
+                            <para>
+                                Module performs self authentication
+                            </para>
+                        </listitem>
+                        <listitem>
+                            <para>
+                                Module is very simple and cannot fail
+                                fatally
+                            </para>
+                        </listitem>
+                    </itemizedlist>
+                </para>
+            </section>
+            <section id="best-practices.how.component.synchronous">
+                <title>Synchronous and Asynchronous Invocation</title>
+                <para>
+                    All method invocations in RAD are
+                    synchronous. Asynchrnous behaviour can be obtained
+                    by adopting a design pattern that relies on the
+                    use of events to provide notifications. Refer to
+                    the section on this in the modules chapter for
+                    more details.
+                </para>
+            </section>
+            <section id="best-practices.how.component.duplication">
+                <title>Duplication</title>
+                <para>
+                    Do not duplicate code from existing CLIs.
+                </para>
+            </section>
+            <section id="best-practices.how.component.client">
+                <title>Client Library Support</title>
+                <para>
+                    RAD modules are designed to have a language
+                    agnostic interface. However, it's possible (and
+                    sometimes advisable) to provide additional
+                    language support via the delivery of a language
+                    specific extension. Such deliverables should be
+                    restricted in use and the main reason for their
+                    existence is to help improve the "fit" of an
+                    interface into a language idiom.
+                </para>
+            </section>
+        </section>
   <section id="best-practices.naming">
     <title>Naming</title>
 
@@ -252,9 +534,169 @@
     </variablelist>
 
   </section>
+</section>
 
   <section>
     <title>Relationships to other agents</title>
   </section>
+  <section><title>Interface Design Examples</title>
+
+  <para>
+      Given the tools described so far in this document, it should be
+      clear how they can be combined to construct an interface with a
+      known design.  Arriving at that design, however, can be a
+      challenge.  There is seldom a single solution for a particular
+      problem, and of the available solutions there may not even be a
+      <quote>best</quote> solution. These examples illustrate the best
+      practices we have described previously.
+  </para>
+    <section><title>User Management Example</title>
+    <para>
+    Object/<acronym>API</acronym> granularity is subjective.  Imagine
+    an interface for managing a user.  The user has a few modifiable
+    properties:
+    </para>
+
+<table><title>Example User Properties</title>
+<tgroup cols='2'>
+<thead>
+<row>
+<entry>Property</entry>
+<entry>Type</entry>
+</row>
+</thead>
+<tbody>
+<row>
+<entry><property>name</property></entry>
+<entry><type>string</type></entry>
+</row>
+<row>
+<entry><property>shell</property></entry>
+<entry><type>string</type></entry>
+</row>
+<row>
+<entry><property>admin</property></entry>
+<entry><type>boolean</type></entry>
+</row>
+</tbody>
+</tgroup></table>
+
+    <para>
+    The API for managing this user might consist solely of a set of
+    attributes corresponding the the above properties.  Alternatively,
+    it could consist of a single attribute that is a
+    <type>structure</type> containing fields that correspond to the
+    properties (possibly more efficient if all properties are usually
+    read or written together).  The object implementing this might be
+    named:
+    </para>
+
+<programlisting>
+com.example.users:type=TheOnlyUser
+</programlisting>
+
+    <para>
+    If instead of managing a single user, you need to manage multiple
+    users, you have a couple choices.  One option would be to modify
+    the interface to use methods instead of attributes, and to add a
+    "user" argument to the methods. e.g.
+    </para>
+
+<programlisting>
+setUserAttributes(username, attributes) throws UserError
+attributes getUserAttributes(username) throws UserError
+</programlisting>
+
+    <para>
+    Given there isn't a lot you can do to a single user, and there are
+    bunch of other global operations you might want to support (e.g.
+    add a user, delete a user, get a list of users), this is pretty
+    reasonable.  We might want to give it a more appropriate name,
+    though:
+    </para>
+
+<programlisting>
+com.example.users:type=UserManagement
+</programlisting>
+      
+    <para>
+    Imagine, though, that there were a lot more properties associated
+    with the user (job history, eye color, favorite dishes at area
+    restaurants), and a lot more things you would want to do with a
+    user (send them email, give them a bonus).  As the server
+    functionality grows, UserManagement's <acronym>API</acronym> grows
+    increasingly cluttered.  It would accumulate a mixture of global
+    operation and per-user operations, and the need for each per-user
+    operation to specify a user to operate on (and specify the errors
+    associated with not finding that user) would start looking
+    redundant.
+    </para>
+
+<programlisting>
+username[] listUsers()
+addUser(username, attributes)
+giveRaise(username, dollars) throws UserError
+fire(username) throws UserError
+sendEmail(username, message) throws UserError
+setUserAttributes(username, attributes) throws UserError
+attributes getUserAttributes(username) throws UserError
+</programlisting>
+
+    <para>
+    A cleaner alternative would be to separate the global operations
+    from the user-specific operations and create two
+    <acronym>API</acronym>s.  The UserManagement object would use the
+    global operations <acronym>API</acronym>:
+    </para>
+
+<programlisting>
+username[] listUsers()
+addUser(username, attributes)
+</programlisting>
+    
+    <para>
+    &hellip; and a separate object for each user would implement the
+    user-specific <acronym>API</acronym>:
+    </para>
+
+<programlisting>
+setAttributes(attributes)
+attributes getAttributes()
+giveRaise(dollars)
+fire()
+sendEmail(message)
+</programlisting>
+
+    <para>
+    (One could argue that <function>fire</function> operates more on
+    the namespace than the user, and should be present in
+    UserManagement where it would need to take a username argument).
+    </para>
+
+    <para>
+    Finally, the different objects would be named such that the
+    different objects could be easily differentiated and be directly
+    accessed by the client:
+    </para>
+
+<programlisting>
+com.example.users:type=UserManagement
+com.example.users:type=User,name=ONeill
+com.example.users:type=User,name=Sheppard
+...
+</programlisting>
+
+    <para>
+    This example also highlights a situation where the
+    <command>rad</command> server may not want to enumerate all objects
+    when a client issues a <literal>LIST</literal> request.  Listing
+    all users may not be particularly expensive, but pulling down a
+    list of potentially thousands of objects on every
+    <literal>LIST</literal> call won't benefit the majority of
+    clients.
+    </para>
+    </section>
+
+</section>
 
 </chapter>
--- a/usr/src/doc/rad-dev/c-concepts-design.xml	Fri Mar 23 12:47:27 2012 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,178 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook V4.4//EN" "http://www.oasis-open.org/docbook/xml/4.4/docbookx.dtd">
-<!--
-  PDL HEADER START
-
-  Public Documentation License Notice
-
-  The contents of this Documentation are subject to the Public
-  Documentation License Version 1.01 (the "License"); you may only
-  use this Documentation if you comply with the terms of this License.
-  A copy of the License is available at
-  http://www.opensolaris.org/os/community/documentation/license.
-
-  PDL HEADER END
-
-  Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
--->
-
-<section><title>Interface Design</title>
-
-<para>
-Given the tools described so far in this chapter, it should be clear
-how they can be combined to construct an interface with a known
-design.  Arriving at that design, however, can be a challenge.  There
-is seldom a single solution for a particular problem, and of the
-available solutions there may not even be a <quote>best</quote>
-solution.  These are some of the factors that should be considered when
-designing an interface for <command>rad</command>.
-</para>
-
-    <section><title>Granularity</title>
-    <para>
-    Object/<acronym>API</acronym> granularity is subjective.  Imagine
-    an interface for managing a user.  The user has a few modifiable
-    properties:
-    </para>
-
-<table><title>Example User Properties</title>
-<tgroup cols='2'>
-<thead>
-<row>
-<entry>Property</entry>
-<entry>Type</entry>
-</row>
-</thead>
-<tbody>
-<row>
-<entry><property>name</property></entry>
-<entry><type>string</type></entry>
-</row>
-<row>
-<entry><property>shell</property></entry>
-<entry><type>string</type></entry>
-</row>
-<row>
-<entry><property>admin</property></entry>
-<entry><type>boolean</type></entry>
-</row>
-</tbody>
-</tgroup></table>
-
-    <para>
-    The API for managing this user might consist solely of a set of
-    attributes corresponding the the above properties.  Alternatively,
-    it could consist of a single attribute that is a
-    <type>structure</type> containing fields that correspond to the
-    properties (possibly more efficient if all properties are usually
-    read or written together).  The object implementing this might be
-    named:
-    </para>
-
-<programlisting>
-com.example.users:type=TheOnlyUser
-</programlisting>
-
-    <para>
-    If instead of managing a single user, you need to manage multiple
-    users, you have a couple choices.  One option would be to modify
-    the interface to use methods instead of attributes, and to add a
-    "user" argument to the methods. e.g.
-    </para>
-
-<programlisting>
-setUserAttributes(username, attributes) throws UserError
-attributes getUserAttributes(username) throws UserError
-</programlisting>
-
-    <para>
-    Given there isn't a lot you can do to a single user, and there are
-    bunch of other global operations you might want to support (e.g.
-    add a user, delete a user, get a list of users), this is pretty
-    reasonable.  We might want to give it a more appropriate name,
-    though:
-    </para>
-
-<programlisting>
-com.example.users:type=UserManagement
-</programlisting>
-      
-    <para>
-    Imagine, though, that there were a lot more properties associated
-    with the user (job history, eye color, favorite dishes at area
-    restaurants), and a lot more things you would want to do with a
-    user (send them email, give them a bonus).  As the server
-    functionality grows, UserManagement's <acronym>API</acronym> grows
-    increasingly cluttered.  It would accumulate a mixture of global
-    operation and per-user operations, and the need for each per-user
-    operation to specify a user to operate on (and specify the errors
-    associated with not finding that user) would start looking
-    redundant.
-    </para>
-
-<programlisting>
-username[] listUsers()
-addUser(username, attributes)
-giveRaise(username, dollars) throws UserError
-fire(username) throws UserError
-sendEmail(username, message) throws UserError
-setUserAttributes(username, attributes) throws UserError
-attributes getUserAttributes(username) throws UserError
-</programlisting>
-
-    <para>
-    A cleaner alternative would be to separate the global operations
-    from the user-specific operations and create two
-    <acronym>API</acronym>s.  The UserManagement object would use the
-    global operations <acronym>API</acronym>:
-    </para>
-
-<programlisting>
-username[] listUsers()
-addUser(username, attributes)
-</programlisting>
-    
-    <para>
-    &hellip; and a separate object for each user would implement the
-    user-specific <acronym>API</acronym>:
-    </para>
-
-<programlisting>
-setAttributes(attributes)
-attributes getAttributes()
-giveRaise(dollars)
-fire()
-sendEmail(message)
-</programlisting>
-
-    <para>
-    (One could argue that <function>fire</function> operates more on
-    the namespace than the user, and should be present in
-    UserManagement where it would need to take a username argument).
-    </para>
-
-    <para>
-    Finally, the different objects would be named such that the
-    different objects could be easily differentiated and be directly
-    accessed by the client:
-    </para>
-
-<programlisting>
-com.example.users:type=UserManagement
-com.example.users:type=User,name=ONeill
-com.example.users:type=User,name=Sheppard
-...
-</programlisting>
-
-    <para>
-    This example also highlights a situation where the
-    <command>rad</command> server may not want to enumerate all objects
-    when a client issues a <literal>LIST</literal> request.  Listing
-    all users may not be particularly expensive, but pulling down a
-    list of potentially thousands of objects on every
-    <literal>LIST</literal> call won't benefit the majority of
-    clients.
-    </para>
-    </section>
-
-</section>
--- a/usr/src/doc/rad-dev/c-concepts.xml	Fri Mar 23 12:47:27 2012 -0400
+++ b/usr/src/doc/rad-dev/c-concepts.xml	Fri Mar 23 12:21:59 2012 -0700
@@ -13,7 +13,7 @@
 
 	PDL HEADER END
 
-	Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
+	Copyright (c) 2010, 2012, Oracle and/or its affiliates. All rights reserved.
 -->
 
 <chapter xmlns:xi="http://www.w3.org/2001/XInclude"><title>Concepts</title>
@@ -63,8 +63,4 @@
 
     <xi:include href="c-concepts-namespace.xml" />
 
-    <!-- Section: Design / Granularity -->
-
-    <xi:include href="c-concepts-design.xml" />
-
 </chapter>