Upload
singingfish
View
483
Download
1
Tags:
Embed Size (px)
Citation preview
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