PETE BACON DARWIN:
So this talk's
going to be a little
bit of light relief.
We've had a lot
of Angular today.
And there's almost no
Angular in this talk at all.
That would've been
a really bad start.
My laptop nearly just
fell off the podium.
So it's also not going
to be quite as attractive
as the Angular
material talk, either.
But hopefully it
will be something
that's interesting
and useful to you.
So who am I?
I'm Pete Bacon Darwin.
I'm the London annex
of the AngularJS team.
I've been working with them
for about a year or so now.
My surname is Bacon Darwin.
Bacon's not my middle name.
It's often confusing
to many people.
So I just thought
I'd point that out.
Today I'm going to
talk about dgeni.
These are the
highlights of the talk.
So if these don't look
interesting to you,
you can go and get
a drink instead.
By the end of today,
I'm hoping that you're
going to be a
little bit inspired
to go and have little look at
dgeni and maybe try it out.
And maybe it will be useful
to you in your own projects.
I'm going to start
with a little quiz.
When I put this talk
together, I didn't
expect there to be quite
so many people in the room.
So I'm not going to actually ask
you to answer these questions.
Because that might
take too long.
OK, so what's the syntax of
the method on the $sce service
in AngularJS they use to
declare a string of HTMLs?
Have a quick think.
TrustAsHtml.
OK, so $sce.trustAsHtml value.
And the value is the
HTML you want to trust.
And with any luck,
we'll have a link
to the website which
contains that information.
This is the slow bit.
So we'll keep going.
Next question, so
AngularJS is easy.
And we all know
AngularJS really well.
So that's an easy question.
Probably there's a few
people using Protractor here,
so you might be able
to answer this one.
How would I access the second
wrote row of this repeater?
It's a repeater,
which has got-- it
repeats over a bunch
of cats in pets.
So we use element by repeater,
cat in pets, row number one
because it's zero based.
I could click on
the link and show
you the documentation
for that as well.
But I suspect it
might take too long.
And we've been talking a lot
about mobile today already.
So here's one for
the Ionic framework.
What's the directive
you'd use if you
wanted to have a
pulldown refresher.
You know, like-- I'm on
Twitter-- when you swipe down,
it refreshes.
And this is ion refresher.
And you can go and see the
documentation for that, too.
So the question is, how do
we know this information?
In the old days, you might
have a nice big, fat reference
book like the Window API
book by Pat [INAUDIBLE].
I had a copy of this
like 10, 15 years ago.
And you would look through
it to find the particular API
item you wanted.
More recently in the
open source community,
you might go to the source.
Because source code is available
in most-- in all open source
projects.
And it's a pretty
good place to find
information about what the
syntax is from [INAUDIBLE],
and maybe even what the
code is going to do for you.
But probably, most
of you are going
to hit some kind of
documentation website.
And projects, especially
open source projects,
go to great efforts
to document--
if they're good projects,
they go to great efforts
to document what they do.
And some of them do a
better job than others.
So I think we can all agree
that we like the docs.
In case you're not
aware of Doctor
Who, this is one of the
more recent doctors.
The key thing
about docs, though,
is that they have to maintain
a level of freshness, yeah.
There's nothing worse
than stale docs.
It's a bit like bread.
I think if you've got to
choose between stale bread
and no bread at
all, you're probably
going to want to go
with no bread at all.
So how do we actually stop
the docs from becoming stale?
The most important feature
is to put into your process.
So whenever you're
changing the code,
you need to change
the docs as well.
And you can do this
through many methods.
You can have a manager
the stands over you
and checks that you're
doing it properly.
But even in that case,
then it might get missed.
So what do we do in AngularJS?
What we do is we put the docs as
close to the code as possible.
And we also store it
inside the same repository.
So whenever we're looking at
a review of a code change,
we can immediately
see whether they've
updated the docs accordingly
and send the message back
to the person who's changed
it to ask them to include,
can change to the docs.
But how do we do
this in AngularJS?
That's the idea.
But how do you
actually achieve this?
So what we did was we
took a trick from JSDoc
and many of these comment based
documentation systems, where
you tag comment, you
tag your documentation
inside a comment that's actually
right next to your code.
And then you need something that
will extract that information
and convert it to a website.
So the AngularJS
team looked at JSDoc.
And it's amazingly powerful.
It parses your code.
And it tries to make the best
guess of what your code does,
which is pretty
impressive, given
how dynamic JavaScript is.
But in AngularJS,
there's a bunch
of concepts which are quite
specific to how we work.
And so things like
controllers and directives,
it's quite hard to
get that information
into a good state
just using JSDoc.
And so in true developer
fashion, we built our own tool.
And this tool was
originally called ngdoc.
And it lived inside
the AngularJS project.
But as the project grew and the
documentation got more complex,
this ngdoc tool got more
and more complicated.
And by the end, it was
about 1,800 lines of code.
1,200 of those were
in a single file.
And it was really hard to find
what was going on in there.
And around about the
end of last year,
I was trying to remove
colons from file
names in the documentation.
Because of course, everyone
knows that in Windows, you
can't have colons in file names.
So this would enable us to build
the Angular docs on Windows
environment if you
want to do that.
Doesn't happen
much inside Google.
And I tried in vain to do this.
But it was so difficult.
The colons were dotted
all over the code.
And so I decided it
was time to refactor.
So thus came dgeni.
So I just took a step back
and started from scratch.
And the idea was
to try and code up
a tool which followed
good design principles.
So everything was going to be
a cohesive little component,
which were decoupled from
the other components.
I wanted to take
lots of the ideas
that we get from AngularJS,
which make it such a joy
to work with, so using
dependency injection.
And of course,
testability is key.
So I wanted to make sure that
the whole code base was really
strongly tested.
And at the moment,
the tool itself
has got 100% code
coverage, in terms of test.
And most of the packages
that we use also have that.
So dgeni was designed
from the beginning
to be fairly flexible
and configurable.
And although it's quite an
immature project in many ways,
it's got some pretty important
projects that are using it.
You'll notice in the
last presentation
that Max kept saying, and we
generate all these documents
from the code.
And it's really cool.
And what he didn't
mention the fact
that it's generated
using dgeni, yeah.
But I'm sure that
the point of that
was so he wouldn't sort of take
the wind from under my sails.
So as he gave me the
opportunity to say that.
But.
You can see there's a
couple of others here.
But what's really
interesting and fascinating
about these four
projects, also Famo.us.
Angular Famo.us, the connection
between Angular and Famo.us
uses dgeni as well.
But I forgot to add that one in.
What's really interesting, I
think, is that each of these
takes a very different
approach to their documentation
generation.
They all produce documents
in slightly different ways
and then present
them to the user
in slightly different ways.
But they don't use huge
amounts of code on top of dgeni
to achieve it.
So let's just quickly look
at each of them in turn.
AngularJS was the main project
that we designed dgeni for.
What it does is it
produces a partial HTML
file for every single
document in your code base.
And then it presents those
using an Angular app.
It also has some
really cool features
like-- which is also in the
Angular Material project
and in Ionic, I
think, where you can
have runnable
examples of your code.
So you actually pull out code
samples from these comments
and make them runnable
inside your documentation.
Protractor takes a
slightly different view.
What it does is it creates
a big JSON document
or object based on all
of the documents that
are in its source code, which
it then provides to the user
through a controller.
What's also interesting
about Protractor
is that, yeah they've
got their own code which
they want to document.
But they actually sit
on top of webDriver,
which is also documented
using JSDoc tags.
And so they've
managed to achieve
a kind of a hybrid
documentation system, which
brings both of these sources
together and produces
pretty useful,
usable documentation.
Angular Material,
as we saw already.
You've seen plenty of
examples of that in action
in the last talk.
And they have got--
again, it's not
that dissimilar to
AngularJS, but they're
using a much more-- a set of
iframes where each component
kind of lives inside
a mini app of its own,
which is generated by dgeni.
And finally, the
Ionic framework have
complete-- as you'd
expect, they've
gone completely in a
different tack altogether.
Their documents get
generated into markdown,
which they upload to
GitHub to be served up
by a Jekyll server, which is
the standard serving mechanism
of GitHub pages.
So you can see
that each of these
is-- they've got a similar goal.
But they're going about
things in different ways.
And I didn't talk about it.
But you'll see that I was
putting these lines of code
markers on each
page, which gives you
an indication of
the amount of effort
that you need to
configure dgeni to achieve
what they want to do.
So let's have a little
look at what dgeni does.
There's only really
three key concepts.
So although many people
come to me saying,
oh, it's got such a
hard learning curve.
And you ironically
haven't really
well documented the tool.
Once you get past
all of that, you'll
find it's actually
really, really not too
much mental effort to use dgeni.
These three concepts are all
you really need to understand.
So a processor is just
a small unit of code
which takes some docs
and does stuff to them
and then returns the new docs.
So maybe it might add some more
documents into the collection.
Or it might manipulate them
in some way or filter them.
And what you do with
dgeni is you just create
a pipeline of these processes.
And dgeni then just,
when you run it,
it just iterates through each
of these processes in turn.
And at the end of it, you
end up having your processed
documents, OK.
This is kind of an
idealistic pipeline.
But it's not actually that
far from what is really
going to happen in your setup.
Each of these processes
and services--
so services are very similar to
what you'd expect in AngularJS.
So if you're using
AngularJS, the concepts
will map nicely over to dgeni.
All of the things like-- so
processes, services, and also
config blocks, which are similar
to the config blocks you'd
get on a module
in Angular, can be
injected via a dependency
injection, which
[INAUDIBLE] kindly wrote for us,
which is using Karma as well.
And all you have to do is
provide factory function
for each of your components.
And it can then depend
upon other services
which can be injected in.
So maybe this is a
little bit small to see
but hopefully it's OK.
In AngularJS, we put everything
into a module and register
components on that module, so
to try not to confuse things,
I've changed the name
to package inside dgeni.
But maybe that will cause
more problems with ES6 coming.
So you create a package.
The package can actually depend
upon other packages, which
means that your components will
be able to use the services
and processes that are in
the packages it depends upon.
And then you just
factory processor
config to register those
components on that package.
What you'll see is that this--
if I didn't mention earlier,
dgeni is a node application.
So we're using require here
to pull in the actual code.
This means that in our
source code project,
we can nicely break
down our codes
into small, manageable chunks.
So let's have a look
at how we've actually
defined the service.
So we call factory and pass
in either the actual service
or require it in.
And this is what
it would look like.
So because it's a
node application,
we're exporting the
factory function.
dgeni is clever
enough to realize
that the name of
the factory function
is the name of the service.
And in this case, we're
just returning a function
that will log the
message that we pass in.
Processes are basically
just specialized services.
They again have a
factory function.
And in this case, I'm actually
depending upon the log service.
So the dependency inject
will bring that in force
as we need it.
And the only thing you really
need to do with a processor
is provide the dollar
process method.
And this is what
will actually do
the processing
inside the pipeline.
In this case, what
we're doing is
we're filtering out all
of the documents that
don't have the ngdoc tag.
And this is something
that actually occurs,
that code's almost
exactly what's
used inside the setup for
the AngularJS project.
We've got other optional
properties as well.
And you can see here,
runafter and runbefore.
This allows us to position our
processor within the pipeline.
So dgeni uses those to work
out where the processor goes.
So if I depend upon a load
of other people's packages,
I don't have to know
about the entire pipeline.
But as long as I know when
my processor needs to fit,
I can insert it at the
right place in the pipeline.
And then finally, to
run dgeni, you just
create-- you require it in.
You make an instance of it.
And you pass in the package
that you have carefully created.
And finally, you
just run Generate
on the instance of dgeni.
And this will
trigger the pipeline.
The processors
will do their job.
And what I didn't mention
earlier is that processors
as well as being able to
take a docs collection
and return a docs
collection, they
can actually run asynchronously
and return a promise
to docs collection.
And in that case,
dgeni's clever enough
to set up the
processing pipeline
as a series of
asynchronous tasks.
So here you can see
that we can actually
deal with what happens when
the generation has finally
finished.
dgeni on its own
doesn't do anything.
It doesn't provide
any processes.
It's just an empty tool.
So you've got to do
some work yourselves.
And you have to provide these
packages and processes that
do the job.
But the nice thing about
that is that you're
completely free to do any
kind of processing you want.
You're not constrained
to only reading in files.
You could get the
files from an-- you
could get the documentation
from like stored procedures
in an SQL server.
Or pull them from a
content management system,
for instance.
And you can then manipulate
them in any way you like.
But there's a lot
of common tasks
that you do need to do in
most generation situations.
So I've created a few packages
that you can rely upon and use.
And these were
primarily developed
for the AngularJS project.
But there's enough
genericism in there
that you can
actually reuse them.
I'm not going to
go into the detail.
If anyone's interested
in really finding out
what these things do,
you can look at the code.
You can come and talk
to me afterwards.
But what I wanted to just finish
with is the last point, which
was in my overview, was
what's in it for you?
You know, why should you
really care about this?
If you had to
start from scratch,
writing all your
processes is going
to require you to do
a fair amount of work.
Using those basic packages
that are available,
that gets you some distance.
But what I've been
working on over the summer
is a sort of proof of concept,
which hopefully will maybe
be interesting to you guys.
What this is is a set
of-- a package which
provides processes
that will actually
go and look at your
application, pause the code,
work out what modules you've
got, what controllers you've
got, and so on, and generate
documentation without you
really having to do too
much configuration at all.
And what I'm hoping to do
is demo this in action.
So this is the
package I've written.
You can see I've provided
a bunch of services.
And there's actually
any two new processes.
One's called pause modules.
And the other one's called
generate module docs.
The pause modules has got
a lot of funky code in it
which uses Esprima to create an
AST of your code, which it then
searches to try and guess
what is going on in your code.
What this means,
though, is that you
have to do a fairly minimal
amount of documenting
in your code.
If we look at a sample
piece of source,
you can see here I'm
declaring a module called mod2
and a controller
called MyControl.
And all I've done in
terms of documentation
is provide a description.
I haven't had to put at name,
or at module, or whatever.
dgeni, the AngularJS
package, which I've defined,
is going to guess
all that for us.
So in order to use this, this
is the set up inside my example,
I'm creating a new package
called dgeni-example.
I'm requiring the
AngularJS package,
which is my new package
I've just written recently.
But this actually also
requires the JSDoc
and the nunjucks packages.
Nunjucks, by the way, is a
rendering engine that will--
that uses similar kind of
mustache style bindings
to render any kind
of text you like,
but mostly you tend
to use it for HTML.
And then there's a little
bit of configuration.
And in these config blocks,
I'm going to specify things
like where the source code
is and where to write it to.
So that's kind of all you really
need to do to use this package.
And when it runs,
you-- oh, and sorry.
And so nunjucks uses templates.
So here's an example
template of what a controller
page is going to look like.
I don't have the beautiful
aesthetic abilities
of some of these
guys like Matias.
So you'll see that my
HTML looks pretty raw.
But I've sneaked in some Angular
material tags in some places.
So you might recognize
some of the styling.
Each template
receives a doc object.
And you can then do whatever you
like with the properties on it.
And so your processors will
have attached properties
to these docs,
which you can then
get a hold of
inside the template.
And you'll end up with something
that looks a bit like this.
This is a controller
that's been generated.
You can see I've pulled in
all the material stuff there.
And then further
down, you can see
that it's using-- it's
actually describing module two.
And it has some
dependencies on module one.
And it's describing the controls
and directives that are there.
So we can possibly,
if I can work out
how to do it-- so this is
what the really beautifully
sculpted output is.
You have to use your
imagination a little bit.
And one of my challenges
to you is that all of this
is driven by templates
and CSS, yeah?
So you can go away,
clone my repository,
provide a beautiful new set
of templates and styles,
and send a pull
request to me and I
will-- any of the really good
ones, I'm going to merge in.
And you can then have plaudits
for being the person who
designed the new start of it.
We have more than one
because, of course,
it's all configurable.
What's really nice about this
is that I'm actually building,
I'm running dgeni using gulp.
You can see here, this is the
gulp watch process in action.
And every time I make
a change to the file,
it's going to re-run dgeni.
If I go and change
some of the source,
like I can go and change
this thing even more,
cool, getItem, or even
more cool helpers, yeah.
I'm not quite as fast
at typing as Andy.
As soon as I hit
Save, then you can
see that dgeni has just run.
You can see here
that it's actually
outputting all of the
processes that the pipeline are
running through.
And if I go to the
page and refresh,
then you can see immediately the
documentation has been updated.
It's just a toy example.
You may or may not
want to do this.
But you can see how
dgeni could fit nicely
into your build process.
So really that's all
there is to say today.
If you want to come
and find out some more
information about dgeni, and
in particular this package,
there's a lot to do on here.
This is definitely
a proof of concept.
I'd really welcome
people's input
and help in making this
something that people-- that
is a turnkey solution for you to
just point at your applications
and generate documentation
really easily.
If we go back to here.
Ah, good old Wi-Fi.
Is it going to refresh?
Come on.
Ah.
AUDIENCE: The presentation
doesn't work [INAUDIBLE].
PETE BACON DARWIN: I know.
I am online.
But the Wi-Fi is struggling.
OK, so what we'll do if I just
zip down and offline mode,
you can see it in place.
So you can go away in code.
You can add new processes.
You can add your own templates.
Many of the applications
that use dgeni
provide a container
application, which is maybe
an Angular app, which then
uses the outputs from dgeni.
So go away, create a nice set
of templates, send them to me,
and I'll be your friend forever.
Here are some links in
order to access all of this.
Angular dgeni is the main tool.
Angular dgeni
packages is the place
where those main packages are.
But my examples are
in my own repository,
which is Pete Bacon
Darwin Organization.
And finally, the main thing
I want to say is thank you.
Because there have been a
handful of contributors.
Many of them are sitting
along the front row here.
I particularly wanted to
say thank you to Stephane.
He's not actually here.
But he's been fantastic
in supporting me.
But also, every
time I make a change
to any documentation
related item inside dgeni,
he hits me with a
translation into French
within like 15
minutes I think is
the slowest he's
managed to do it.
So given that we're
in Paris today,
you'll be delighted to
know that all of the read
mes inside the dgeni project
are also available in French
as well.
If anyone wants to translate
them into other languages,
then I'd be happy
to hear from you.
So thank you very much
for listening to me today.
And come and find me if you want
to come and talk about dgeni.
[APPLAUSE]
