"You may be an ambassador to England or France
You may like to gamble, you might like to dance
You may be the heavyweight champion of the world
You may be a socialite with a long string of pearls

But you’re gonna have to serve somebody, yes indeed
You’re gonna have to serve somebody."

dylan

Serve Everybody

Strategies for helping your clients participate in the open source community

Introductions

Marcus Estes

Jonathan Hedstrom

opensourcery

There are two components to this "release more client code" strategy:

And they are:

  1. Business development and legal strategies
  2. Technical and process-oriented strategies

Let's begin where all client work begins. With the business side.

Don't just capture requirements.

Help create them.

If you want to release useful code, you've got to collaborate with your clients to keep organization-specific requirements to a minimum.

This is good for your clients. Chances are, they can't afford the complexity that they desire.

Talk them down by proposing simpler solutions. Be creative.

Be forthright about your release strategy. Make the case:

  1. Releasing code will induce others to help you support it.
  2. Beloved modules get version updates. If it just sits on your server, you'll have to pay for the upgrade.
  3. If you're lucky, you'll get free feature enhancements.

Create a solid legal foundation for your release

  1. Retain ownership.
  2. Release to your client under an open license.
  3. Sounds crazy, but it works.

Meet objections:

  1. If you want to incorporate your own code, you can't assign them ownership of it.
  2. This is just the way the open source industry works.
  3. Consider non-competes. But there should be a termination date. (And double your rate.)

Development practices that encourage the release of code

  1. Workflow that encourages or requires pushing patches upstream
  2. Well crafted features
  3. Reusable themes
  4. Installation profiles
  5. Putting it all together

There will always be bugs

(and missing features)

drush make

projects[views][subdir] = "contrib"
projects[views][version] = "2.11"
; http://drupal.org/node/862072
projects[views][patch][] = "http://drupal.org/files/issues/views.862072.patch"
	  

docs directory

.htaccess
README.txt
vertical_tabs.626126.patch
views.862072-7.patch
	  

Well crafted features

Avoid forking features on a per-project basis

Instead, consider using alter hooks when possible

Reusable themes

(sub sub themes!)

Build installation profiles

(until the last possible moment)

	      if ($task == 'profile') {
   // Insert default user-defined node types into the database. For a complete
    // list of available node type attributes, refer to the node type API
    // documentation at: http://api.drupal.org/api/HEAD/function/hook_node_info.
    $types = array(
      array(
        'type' => 'page',
        'name' => st('Page'),
        'module' => 'node',
        'description' => st("A page is a simple method for creating and displaying information that rarely changes, such as an \"Abo
ut us\" section of a website. By default, a page entry does not allow visitor comments and is not featured on the site's initial hom
e page."),
        'custom' => TRUE,
        'modified' => TRUE,
        'locked' => FALSE,
        'help' => '',
        'min_word_count' => '',
      ),
    );

    foreach ($types as $type) {
      $type = (object) _node_type_set_defaults($type);
      node_type_save($type);
    }

    // Default page to not be promoted, and have comments disabled, and create new revisions.
    variable_set('node_options_page', array('status', 'revision'));
    variable_set('comment_page', COMMENT_NODE_DISABLED);

    // Don't display date and author information for page nodes by default.
    $theme_settings = variable_get('theme_settings', array());
    $theme_settings['toggle_node_info_page'] = FALSE;
    variable_set('theme_settings', $theme_settings);

    // Admin theme.
    variable_set('admin_theme', 'rubik');

	  
	      if ($task == 'profile') {
   // Insert default user-defined node types into the database. For a complete
    // list of available node type attributes, refer to the node type API
    // documentation at: http://api.drupal.org/api/HEAD/function/hook_node_info.
    $types = array(
      array(
        'type' => 'page',
        'name' => st('Page'),
        'module' => 'node',
        'description' => st("A page is a simple method for creating and displaying information that rarely changes, such as an \"Abo
ut us\" section of a website. By default, a page entry does not allow visitor comments and is not featured on the site's initial hom
e page."),
        'custom' => TRUE,
        'modified' => TRUE,
        'locked' => FALSE,
        'help' => '',
        'min_word_count' => '',
      ),
    );

    foreach ($types as $type) {
      $type = (object) _node_type_set_defaults($type);
      node_type_save($type);
    }

    // Default page to not be promoted, and have comments disabled, and create new revisions.
    variable_set('node_options_page', array('status', 'revision'));
    variable_set('comment_page', COMMENT_NODE_DISABLED);

    // Don't display date and author information for page nodes by default.
    $theme_settings = variable_get('theme_settings', array());
    $theme_settings['toggle_node_info_page'] = FALSE;
    variable_set('theme_settings', $theme_settings);

    // Admin theme.
    variable_set('admin_theme', 'rubik');

	  
X

Profiler library

http://drupal.org/project/profiler

Enable modules

	    dependencies[] = foobar
	    dependencies[] = custom_feature
	  

Set variables

	    variables[site_name] = My Awesome Site
	    variables[site_frontpage] = welcome
	  

Declare a base profile

	    base = my_base_profile
	  

Create users, nodes, and run install hooks

	    ; Create an administrative user
users[admin][uid] = 1
users[admin][name] = Administrator
users[admin][mail] = webmaster@example.com
users[admin][roles] = administrator
users[admin][status] = 1

; About page.
nodes[about][type] = page
nodes[about][title] = About My Site
nodes[about][body] = Placeholder content for the about page.
nodes[about][uid] = 1
nodes[about][menu][link_title] = About
nodes[about][menu][menu_name] = primary-links
nodes[about][path] = about
	  

(Has a very verbose and helpful README.txt)

Putting it all together

Questions?

Thank you