Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010

Post on 29-Jun-2015

483 views 1 download

Tags:

Transcript of Don't RTFM, WTFM - Open Source Documentation - German Perl Workshop 2010

DON’T RTFM - WTFMWrite the F--king Fantastic Manual

Or how I learned to stop worrying and love the code

or...

Newbies write the best docs.I will teach you how to be a newbie all over again!

My background

Like most perl programmers I’m self taught

But I learned very slowly since 1999

Why?

Programming is 10% of my job and voluntary.

Documentation assumes too much pre-existing knowledge

My background - cont

Teaching Statistics for science and business students

They hate statistics, Why?

How can I make them hate statistics less?

The problem of contrived examples.

Our goal is to prime them to deal with real world problems in the future.

How did I solve this problem?Catalyst

Catalyst::Manual::Tutorial

didn’t work12:23 <@kd> purl, doesn't work?

12:23 < purl> Look buddy, doesn't work is a strong statement. Does it sit on the couch all day? Is it making faces at you? Does it want more money? Is it sleeping with your girlfriend? Please be specific!

Fixed in Catalyst 5.65: 21st Feb 2006 :13 months since the beginning of the project!

Remove irrelevant information: created "MyApp" created "MyApp/script"- created "MyApp/lib"- created "MyApp/root"- created "MyApp/root/static"- created "MyApp/root/static/images"- created "MyApp/t"- created "MyApp/t/Model"- created "MyApp/t/View"- created "MyApp/t/Controller"- created "MyApp/lib/MyApp"- created "MyApp/lib/MyApp/Model"- created "MyApp/lib/MyApp/View"- created "MyApp/lib/MyApp/Controller"- created "MyApp/lib/MyApp.pm"- created "MyApp/Build.PL"- created "MyApp/Makefile.PL"- created "MyApp/README"- created "MyApp/Changes"- created "MyApp/t/01app.t"- created "MyApp/t/02pod.t"- created "MyApp/t/03podcoverage.t"- created "MyApp/root/static/images/catalyst_logo.png"- created "MyApp/root/static/images/btn_120x50_built.png"- created "MyApp/root/static/images/btn_120x50_built_shadow.png"- created "MyApp/root/static/images/btn_120x50_powered.png"- created "MyApp/root/static/images/btn_120x50_powered_shadow.png"- created "MyApp/root/static/images/btn_88x31_built.png"- created "MyApp/root/static/images/btn_88x31_built_shadow.png"- created "MyApp/root/static/images/btn_88x31_powered.png"- created "MyApp/root/static/images/btn_88x31_powered_shadow.png"- created "MyApp/root/favicon.ico"- created "MyApp/script/myapp_cgi.pl"- created "MyApp/script/myapp_fastcgi.pl"- created "MyApp/script/myapp_server.pl"- created "MyApp/script/myapp_test.pl"+ ... output snipped created "MyApp/script/myapp_create.pl"

Make the supplied code work:

- sub greet : Local- {- my ($self, $context) = @_;+ sub greet : Local {+ my ($self, $c) = @_; - my $name = $context->req->params->{name};- $context->log->debug("Got name: $name\n");+ my $name = $c->req->param('name');+ $c->log->debug("Got name: $name\n"); - if(!$name)- {- $context->stash->{message} = 'Please fill in a name!';+ if ($c->req->method eq 'POST') {+ if(!$name) {+ $c->stash->{message} = 'Please fill in a name!';+ }+ else {+ $c->stash->{message} = "Hello $name!"; }- else- {- $context->stash->{message} = "Hello $name!"; }- $context->stash->{template} = 'greet.tt';+ $c->stash->{template} = 'greet.tt'; }

Show that the code works

Always provide a reference implementation:

The first fully working Catalyst Tutorial:

http://dev.catalystframework.org/old-wiki/attachment/wiki/WikiStart/tutorial.tar.gz

This set up the future of Catalyst

Catalyst code is working code

Catalyst educational material is always accompanied by working code.

The original Catalyst tutorial lasted 9 months

Kennedy Clark turned up and wrote a big tutorial

A real published author :)

(we have a history of these in Catalyst)

On to the future

The new tutoriallib/Catalyst/Manual/Tutorial.pod

lib/Catalyst/Manual/Tutorial/Intro.pod

lib/Catalyst/Manual/Tutorial/CatalystBasics.pod

lib/Catalyst/Manual/Tutorial/BasicCRUD.pod

lib/Catalyst/Manual/Tutorial/Authentication.pod

lib/Catalyst/Manual/Tutorial/Authorization.pod

lib/Catalyst/Manual/Tutorial/AdvancedCRUD.pod

lib/Catalyst/Manual/Tutorial/Testing.pod

lib/Catalyst/Manual/Tutorial/Debugging.pod

lib/Catalyst/Manual/Tutorial/Appendices.pod

Always give examples

You can obtain the code for all the tutorial examples from the catalyst subversion repository by issuing the command:

svn co http://dev.catalyst.perl.org/repos/Catalyst/tags/examples/Tutorial/MyApp/5.7/ CatalystTutorial

This will download the current code for each tutorial chapter in the CatalystTutorial directory. Each example application directory has the same name as the tutorial chapter.

Reduce the barrier to entry

Sometimes OSS programmers can seem hostile.

Aim to only have to answer the same question once.

Write the answer down

In the pod

In the wiki

Teach the bot

My most useful factoid04:45 <@kd> purl, make_schema_at?

04:45 <+purl> make_schema_at is what i want

04:47 <@kd> no purl, make_schema_at is perl -MDBIx::Class::Schema::Loader=make_schema_at,dump_to_dir:./lib -e 'make_schema_at("My::Schema", { debug => 1, db_schema => "myschemaname", components =>["InflateColumn::DateTime"] },["dbi:Pg:host=localhost;dbname=mydbname", "user", "pass" ])'

04:47 <+purl> okay, kd.

Summary:

Always always always provide a working example.

Use your tests as a basis if you want.

Point the users to the tests in the pod if necessary.

Why?

To avoid constantly being asked stupid questions.

If you don’t, what happens?

Nobody cares because nobody uses your code.

or: You’re constantly asked stupid questions

or: If you’re lucky, someone like me comes along, asks the stupid questions, and writes the answers down.

The third option doesn’t happen often.

Cognitive Load Theory

An educational technique used in school Maths and Science Education.

KISS - Keep It Simple Stupid

Working memory has a finite capacity:

7±2 items

We should aim to ensure that only relevant items are presented to the reader, so their memory capacity isn’t overloaded.

The Parts of Cognitive Load

Intrinsic (internal) cognitive load:

Task relevant demands

e.g. Programming logic

Extrinsic cognitive load:

Business logic

Prerequisite knowledge

The components of software

Programming logic

Task logic

Business logic

Business logic can be big, complex and poorly defined.

Add a dash of chaos theory

e.g. a three parameter model with a single outcome variable can result in substantial divergence after a single

change in initial conditions.

It only needs 3 parameters to create chaos.

Business logic always has > 3 parameters

How to minimise chaos

Make examples artificial and contrived.

How do we do this without being boring and pointless?

Case study. Catalyst Book

LolCatalyst

Translate snippets of text to LolCat.

CPAN module: Acme::LOLCAT

Educational purpose

Show how to display a web page

Show how to create a web service

Show that authentication is possible

Catalyst::Helper::AuthDBIC

(or what I spent my time on when I visited Shadowcat to plan the book)

Assumed knowledge

Basic HTTP

GET v POST requests

Basic Perl data structures

What’s an editor and how do I use it?

How do I run a perl script?

How do I install CPAN modules.

Assumed knowledge cont.

If the reader doesn’t possess the assumed knowledge the extrinsic and intrinsic cognitive load are both high.

Authentication

Authentication is complicated

Instead of explaining it, I wrote a Catalyst::Helper that modifies an existing application

Thank you PPI :)

Problem solved in a single page of text.

Web service

Catalyst web services are simple

In LolCatalyst/Controller/Root:sub translate_service : Local { my ($self, $c) = @_; $c->forward('translate'); $c->stash->{current_view} = 'Service';}

In LolCatalyst/View/Service:

package LolCatalyst::View::Service;use strict;use base 'Catalyst::View::JSON';__PACKAGE__->config({ expose_stash => [ qw/lol result/ ] });1;

So far so good.

No business logic

Some programming logic

Basic introduction to some core catalyst concepts

A Controller with minimal business logic

sub default :Path { my ( $self, $c ) = @_; $c->response->status(404); $c->response->body( 'Page not found' );}

sub translate :Local { my ($self, $c) = @_; my $lol = $c->req->body_params->{lol}; # only for a POST request # $c->req->params->{lol} would catch GET or POST # $c->req->query_params would catch GET params only $c->stash( lol => $lol, result => $c->model('Translate')->translate($lol), template => 'index.tt', );}

Assumed knowledge

New knowledge

Total number of concepts added

View

Service

Dispatch

We still have room for 4±2

Template View (almost identical to Service view)

Model:

package LolCatalyst::Lite::Model::Translate; use strict;use warnings;use parent 'Catalyst::Model';use Acme::LOLCAT ();use Memoize;memoize ('translate');sub translate { my ($self, $text) = @_; return Acme::LOLCAT::translate($text);}1;

Error trapping (in Controller::Root):

sub end : ActionClass('RenderView') { my ($self, $c) = @_; my $errors = scalar @{$c->error}; if ($errors) { $c->res->status(500); $c->res->body('internal server error'); $c->clear_errors; }}

Assumed knowledge

Not very different from “normal” programing!

The final result

A very simple application

Minimal extra learning required to understand the model

Minimal programming logic features.

What next?

Get mst to refactor

Let’s make a generic translation application.

Many more moving parts.

Large conceptual territory to cover

How do we make sure that we only present relevant information to the reader?

Git based education.

Git - the other meaning

Urbandictionary.com:

A completely ignorant, childish person with no manners

Total and utter tosser who is incapable of doing anything other than annoying people, and not in a way that is funny to others

Means idiot or rotter. Often used affectionately like bugger, but when used seriously is probably more potent (but less rude) than the worst swear words.

Git as an educational resource: the approach

Each commit introduces a single new idea to the reader

Advantages:

Clarity

Disadvantages:

Labour intensive

Need to rewrite history - story telling rather than “real” development

But we can count the number of concepts introduced easily by looking at the diffs.

Extending LolCatalyst

review git history

number of concepts per commit

shows how clearly we have explained the problem

Case study - Moose Cookbook

The Moose cookbook is generally excellent and comprehensive.

but ...

The early examples are simple, but the become more complex quickly

Where’s the code?

Reducing complexity

Reduce business logic

reduce extrinsic cognitive load

Simplify programming logic

a delicate balance between being meaningful and too contrived

package Point;

package Point; use Moose;

has 'x' => (isa => 'Int', is => 'rw', required => 1); has 'y' => (isa => 'Int', is => 'rw', required => 1);

sub clear { my $self = shift; $self->x(0); $self->y(0); }

package Point3D;

package Point3D; use Moose;

extends 'Point';

has 'z' => (isa => 'Int', is => 'rw', required => 1);

after 'clear' => sub { my $self = shift; $self->z(0); };

Where is the code - hidden in the pod

=begin testing

my $point = Point->new( x => 1, y => 2 );isa_ok( $point, 'Point' );isa_ok( $point, 'Moose::Object' );

is( $point->x, 1, '... got the right value for x' );is( $point->y, 2, '... got the right value for y' );

$point->y(10);is( $point->y, 10, '... got the right (changed) value for y' );

dies_ok { $point->y('Foo');}'... cannot assign a non-Int to y';

dies_ok { Point->new();}'... must provide required attributes to new';

$point->clear();

is( $point->x, 0, '... got the right (cleared) value for x' );is( $point->y, 0, '... got the right (cleared) value for y' );

# check the type constraints on the constructor### the remaining test code is not relevant to the example### and should be elsewhere!!!

ALWAYSADVERTISE YOUR EXAMPLES

Unadvertised examples are extra extrinsic congnitive load

ASSUME I WILL NEVER READ YOUR SOURCE CODE

TIME TO WORK

Contributors should get a copy of:

http://github.com/singingfish/German-Perl-Documentation-Workshop

or

http://xrl.us/bhn6xm

Task 1: Moose+DBICLots of interest in how to integrate Moose with DBIC

No example driven documentation on how to do this

No example driven documentation on why you want this

Good starting material:

DBIx::Class::Manual::Example

http://localhost:2963/~frew/DBIx-Class-0.08122/DBIx-Class-0.08122/lib/DBIx/Class/Manual/

Task 2: Better explanation of Moose Roles

Moose Roles

The existing Cookbook Examples have too much business logic.

There are inline test examples, but unadvertised

http://localhost:2963/~flora/Moose-1.06/Moose-1.06/lib/Moose/Cookbook/Roles/Recipe1.pod

Task 3: CoercionToo confusing. Too much cognitive load

Too many ways to do it?

Show the simplest way

Show a more flexible way

Minimise business logic

http://localhost:2963/~flora/Moose-1.06/Moose-1.06/lib/Moose/Cookbook/Basics/Recipe5.pod

Task 4: Better explanation of metaprogramming

Why metaprogramming?

Why make_immutable

Why not make_immutable

Where’s the simple example working code?

http://localhost:2963/~flora/Moose-1.06/Moose-1.06/lib/Moose/Cookbook/Meta/Recipe1.pod

But ...I can’t write well

I don’t speak good enough English.

Catalyst Process:

someone writes docs.

kd reviews docs for content (major edits)

the_jester reviews docs for grammar and spelling (minor edits)

Your writing and language skills don’t matter because someone else will fix the problems

Task 5: Moose::Manual::Index

Let’s crowdsource!

Read a moose perldoc page.

Write down the names of the important concepts

If you want write an explanation

If you can’t work this out, just write the name of the concept

Write a short explanation of the concept.

Pod formatEveryone read a Moose man page

Each time you see a new concept, write it down:

=head2 CONCEPT

name of concept

=head3 EXPLANATION

what it does here

=head3 MENTIONS

where it’s mentioned elsewhere in the docs

Patches welcome

To the github repository

Or patches/files to diment@gmail.com