Max Rabkin | 13 Nov 20:51
Picon

Writing great documentation

Haskellers,

I have heard many complaints about the average quality on
documentation. Therefore, I'd like to encourage you all to read Jacob
Kaplan-Moss's series on writing great documentation:
http://jacobian.org/writing/great-documentation/. The articles are
themselves well-written and contain excellent advice (though I
disagree somewhat with the comments on automatically-generated
documentation: I find many libraries are excellently haddocumented).
Jacob Kaplan-Moss is a developer on the Django project, which is well
known for the quality of its documentation.

One issue he brings up is having different types of documentation. My
impression of many Haskell libraries (my own included) is that, while
they may have good reference documentation, they lack tutorials and
topic guides.

Perhaps we could bring up some examples of Haskell projects with
particularly good documentation, as examples to look up to. XMonad has
very good overviews and guides for developers, and I like how each
user-facing xmonad-contrib module gives a small snippet showing how to
use it in ones own config. One area where I think it could be improved
(and I plan to do some work on this when I have more free time) is in
topical guides on things like "how to write your own layout".

--Max
Tom Tobin | 13 Nov 21:01
Gravatar

Re: Writing great documentation


On Fri, Nov 13, 2009 at 1:51 PM, Max Rabkin <max.rabkin <at> gmail.com> wrote: > I have heard many complaints about the average quality on > documentation. Therefore, I'd like to encourage you all to read Jacob > Kaplan-Moss's series on writing great documentation: > http://jacobian.org/writing/great-documentation/. The articles are > themselves well-written and contain excellent advice (though I > disagree somewhat with the comments on automatically-generated > documentation: I find many libraries are excellently haddocumented). > Jacob Kaplan-Moss is a developer on the Django project, which is well > known for the quality of its documentation.
Some of the advice is decent, but some (e.g., "edit on paper", "avoid editing and writing simultaneously") I could never bring myself to do; the ability to continuously revise mid-stream is what keeps me *sane*, and the only reason I can write at all. (It probably helps — or hurts? — that I'm positively neurotic when it comes to grammar and usage.)
Simon Michael | 13 Nov 21:58
Favicon

Re: Writing great documentation

Thanks for this topic and the link; I'm going to try to use it to improve the docs for hledger and my other projects.

(And I agree, he's wrong about auto-generated docs.)

I seem to remember admiring Parsec's documentation. Though, that reminds me..

A very common problem with online docs is fragmentation. Eg, often to learn haskell libraries the reader
has to visit 
multiple sites, or multiple locations and formats from one site, and sort through multiple versions of the
docs, to 
piece together a full picture. You may have the original outdated but most complete docs; the newer, less
complete 
version hosted on haskell.org; the similar but different version pasted on the haskell wiki with
discussion; the 
clarifying (or not) blog articles; the api docs on hackage corresponding to your installed software, etc.

To avoid this, I think project leaders need to (a) maintain and clearly identify one canonical starting
point for docs 
(I favour the hackage page for small projects, a dedicated site or a page on the wiki for larger ones); and (b) 
continually seek out, purge and delete out-dated/inconsistent/duplicated docs wherever they be hosted
- get them off the 
net.
Max Rabkin | 13 Nov 22:20
Picon

Re: Re: Writing great documentation


On Fri, Nov 13, 2009 at 10:58 PM, Simon Michael <simon <at> joyful.com> wrote: > A very common problem with online docs is fragmentation.
Absolutely! Is it possible to include non-haddock documentation in a cabal package. Is it possible to have it readable on Hackage? I think this would help with the fragmentation and versioning issues. One option is to have haddock-only modules for non-reference documentation (xmonad-contrib does this), and I think at the moment it is a good option, but it does have disadvantages. It may not be clear from the outline where documentation can be found, and it clutters up the module namespace. Perhaps we could add support for a Documentation-Modules field in cabal files, which would separate these modules in the outline, and not install them but only their documentation. --Max
Magnus Therning | 13 Nov 22:57
Gravatar

Re: Re: Writing great documentation


On 13/11/09 21:20, Max Rabkin wrote: > On Fri, Nov 13, 2009 at 10:58 PM, Simon Michael <simon <at> joyful.com> wrote: >> A very common problem with online docs is fragmentation. > > Absolutely! Is it possible to include non-haddock documentation in a > cabal package. Is it possible to have it readable on Hackage? I think > this would help with the fragmentation and versioning issues. > > One option is to have haddock-only modules for non-reference > documentation (xmonad-contrib does this), and I think at the moment it > is a good option, but it does have disadvantages. It may not be clear > from the outline where documentation can be found, and it clutters up > the module namespace. Perhaps we could add support for a > Documentation-Modules field in cabal files, which would separate these > modules in the outline, and not install them but only their > documentation.
I feel the Haskell Wiki is a great place to keep non-reference docs. That's what I opted to do for dataenc, and will most likely do if I ever get around to putting other modules on hackage. /M -- -- Magnus Therning (OpenPGP: 0xAB4DFBA4) magnus@therning.org Jabber: magnus@therning.org http://therning.org/magnus identi.ca|twitter: magthe
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
Duncan Coutts | 13 Nov 23:31

Re: Re: Writing great documentation

On Fri, 2009-11-13 at 23:20 +0200, Max Rabkin wrote:
> On Fri, Nov 13, 2009 at 10:58 PM, Simon Michael <simon <at> joyful.com> wrote:
> > A very common problem with online docs is fragmentation.
> 
> Absolutely! Is it possible to include non-haddock documentation in a
> cabal package. Is it possible to have it readable on Hackage?

Not yet.

Want to volunteer?

http://hackage.haskell.org/trac/hackage/ticket/330

It's partly a matter of tasteful design and partly implementation. The
same person/people do not need to do both bits. Thrashing out a detailed
and workable design would get us most of the way there.

> I think this would help with the fragmentation and versioning issues.

Yes, I agree.

> One option is to have haddock-only modules for non-reference
> documentation (xmonad-contrib does this), and I think at the moment it
> is a good option, but it does have disadvantages. It may not be clear
> from the outline where documentation can be found, and it clutters up
> the module namespace. Perhaps we could add support for a
> Documentation-Modules field in cabal files, which would separate these
> modules in the outline, and not install them but only their
> documentation.

I rather like the idea of using markdown (pandoc) for separate
non-reference docs like man pages, tutorials, user guides etc rather
than trying to make haddock do everything.

Duncan
Gour | 13 Nov 23:41
Gravatar

Re: Writing great documentation

On Fri, 13 Nov 2009 22:31:54 +0000

>>>>>> "Duncan" == Duncan Coutts <duncan.coutts <at> googlemail.com> wrote:
Duncan> I rather like the idea of using markdown (pandoc) for separate Duncan> non-reference docs like man pages, tutorials, user guides etc Duncan> rather than trying to make haddock do everything. I'd agree only with the exception to use rst/docutils/sphinx which produces nice html/pdf. (Yeah, I know it's not Haskell, but...) Sincerely, Gour -- -- Gour | Hlapicina, Croatia | GPG key: F96FF5F6 ----------------------------------------------------------------
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe
John O'Donnell | 14 Nov 12:52
Picon
Picon
Favicon

Re: Re: Writing great documentation[MESSAGE NOT SCANNED]

I agree with Duncan's comment:
> I rather like the idea of using markdown (pandoc) for separate
> non-reference docs like man pages, tutorials, user guides etc rather
> than trying to make haddock do everything.
>

In one of my projects (Hydra and Sigma), I use pandoc for the bulk of 
the documentation, and integrate this with haddock documentation for the 
parts of the documentation that haddock can do (which is a small part of 
it).  This is all coordinated by a (rather clunky) Setup.hs.  The whole 
thing isn't very elegant, but it works robustly on both Linux and 
Windows.  That's a big advantage of pandoc: you can install it with 
cabal and use it in your Setup, so it isn't necessary to do any shell 
scripting, which can cause portability problems.  I'll attach the 
Setup.hs file.

One of the central issues here is *where* the documentation files go.  I 
don't like the existing situation, where haddock documentation goes into 
a standard place, and presumably other documentation goes somewhere 
else.  It's surely better to have all the documentation for a package in 
one directory, with all the parts linked together.  So my setup makes a 
directory, builds the haddock and pandoc pieces of the documentation, 
copies (or build)  it all into the directory, and then the contents of 
this directory is listed under data-files in the cabal file.  The result 
is that building the system produces a complete self-contained directory 
and the executable application is able to find its own documentation 
files.  This is usful in a GUI program, for example, where it's nice to 
make the documentation availble under the Help menu.

Something along these lines (with a cleaner design) would be generally 
useful.

John O'Donnell

On 11/13/2009 10:31 PM, Duncan Coutts wrote:
> On Fri, 2009-11-13 at 23:20 +0200, Max Rabkin wrote:
>
>> On Fri, Nov 13, 2009 at 10:58 PM, Simon Michael<simon <at> joyful.com>  wrote:
>>
>>> A very common problem with online docs is fragmentation.
>>>
>> Absolutely! Is it possible to include non-haddock documentation in a
>> cabal package. Is it possible to have it readable on Hackage?
>>
> Not yet.
>
> Want to volunteer?
>
> http://hackage.haskell.org/trac/hackage/ticket/330
>
> It's partly a matter of tasteful design and partly implementation. The
> same person/people do not need to do both bits. Thrashing out a detailed
> and workable design would get us most of the way there.
>
>
>> I think this would help with the fragmentation and versioning issues.
>>
> Yes, I agree.
>
>
>> One option is to have haddock-only modules for non-reference
>> documentation (xmonad-contrib does this), and I think at the moment it
>> is a good option, but it does have disadvantages. It may not be clear
>> from the outline where documentation can be found, and it clutters up
>> the module namespace. Perhaps we could add support for a
>> Documentation-Modules field in cabal files, which would separate these
>> modules in the outline, and not install them but only their
>> documentation.
>>
> I rather like the idea of using markdown (pandoc) for separate
> non-reference docs like man pages, tutorials, user guides etc rather
> than trying to make haddock do everything.
>
> Duncan
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe <at> haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>

import Distribution.Simple
import System.Directory
import System.FilePath
import Text.Pandoc
import Text.Pandoc.Shared
import qualified System.IO.UTF8 as U

-- To do:

main = defaultMainWithHooks hooks

hooks :: UserHooks
hooks = simpleUserHooks {postBuild = postBuildHook}

------------------------------------------------------------------------

{- Haddock creates its documentation in the form of a set of files in
dist/doc/html/Hydra.  These files have names matching *.html, *.gif,
*.css, *.js, Hydra.haddock.  After running haddock, we have:

  dist/doc/html/Hydra/(files created by Haddock)

Hydra has much more extensive documentation, produced by pandoc from
sources in doc.  The top level file in this is index.html.  To avoid
conflicts between the primary Hydra documentation and the API
documentation from haddock, the following steps are taken:

  1. A list of files in dist/doc/html/Hydra/ is created,
     and named haddock_files

  2. A directory dist/doc/html/Hydra/haddock is created

  3. All the files in dist/doc/html/Hydra[haddock_files] are copied to
     dist/doc/html/Hydra/haddock

  4. All the files in dist/doc/html/Hydra[haddock_files] are removed

  5. Pandoc is run on the documentation source files, with the results
     placed in dist/doc/html/Hydra.  These files contain relative
     pointers (URLs) into the haddock documentation.

The result is a documentation directory in the same place Cabal
expects to find it --- dist/doc/html/Hydra --- which contains the
Hydra documentation as well as the API reference produced by haddock.

 -}

------------------------------------------------------------------------

{- The csslink string is html to be incorporated into the page; it
loads the css style file.  This is placed into the haddock directory,
and given the name haddock.css, so the html files generated by haddock
will find it.  The files generated by pandoc also look there, so only
one copy of the style file needs to be created. -}

csslink :: String
csslink =
  "<link rel=\"stylesheet\" " ++
  "href=\"style.css\" type=\"text/css\" media=\"all\" />"

------------------------------------------------------------------------

postBuildHook args flags packageDescription localBuildInfo =
  do putStrLn (take 72 (repeat '-'))
     putStrLn "running postBuildHook"

     createDirectoryIfMissing True
       (joinPath ["doc", "html"])

     createDirectoryIfMissing True
       (joinPath ["doc", "html", "figures"])

     putStrLn "Running pandoc..."
     runPandoc
     putStrLn "Pandoc finished"

     putStrLn (take 72 (repeat '-'))

     figure_files <- getDirectoryContents
                       (joinPath ["doc", "src", "figures", "xfig"])

     putStrLn ("Figure files: " ++
                concat (map ((++"\n") . show) figure_files))

     copy_files
       (joinPath ["doc", "src", "figures", "xfig"])
       (joinPath ["doc", "html", "figures"])
       figure_files

     copyFile
       (joinPath ["doc", "src", "style.css"])
       (joinPath ["doc", "html", "style.css"])

     copyFile
       "Sigma16.cabal"
       (joinPath ["doc","html", "Sigma16.cabal"])

--     copyFile
--       (joinPath ["examples", "Add.asm.src.txt"])
--       (joinPath ["doc", "html", "Add.asm.src.txt"])

     putStrLn (take 72 (repeat '-'))

     return ()

------------------------------------------------------------------------

move_files src dest [] = return ()
move_files src dest (x:xs) =
  do putStrLn x
     if head x == '.' || x=="haddock" || x=="figures"
       then putStrLn ("Skipping file <" ++ x ++ ">")
       else do let srcpath = joinPath [src,x]
               let destpath = joinPath [dest,x]
               putStrLn ("Moving <" ++ srcpath ++
                         "> to <" ++ destpath ++ ">")
               renameFile srcpath destpath
     move_files src dest xs

copy_files src dest [] = return ()
copy_files src dest (x:xs) =
  do putStrLn x
     let ext = takeExtension x
     let srcpath = joinPath [src,x]
     let destpath = joinPath [dest,x]
     putStrLn ("filepath = <" ++ x ++ "> extension = <" ++ ext ++ ">")
     if head x == '.' || ext/=".png"
       then putStrLn ("Skipping file <" ++ x ++ ">")
       else do putStrLn ("Copying <" ++ srcpath ++
                         "> to <" ++ destpath ++ ">")
               copyFile srcpath destpath
     copy_files src dest xs

------------------------------------------------------------------------

markdownToHtml :: WriterOptions -> String -> String
markdownToHtml opts =
  (writeHtmlString opts) . readMarkdown defaultParserState

mkHtml :: String -> String -> WriterOptions -> IO ()
mkHtml infilepath outfilepath opts =
  do inp <- U.readFile infilepath
     let outp = markdownToHtml opts inp
     writeFile outfilepath outp

runPandoc =
  do 
     putStrLn "Building index.html"

     mkHtml
       (joinPath ["doc", "src", "index.txt"])
       (joinPath ["index.html"])
       (defaultWriterOptions 
         { writerStandalone = True
         , writerIncludeBefore = csslink
         })

     mkHtml
       (joinPath ["doc", "src", "overview.txt"])
       (joinPath ["doc", "html", "overview.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         })

     mkHtml
       (joinPath ["doc", "src", "programming.txt"])
       (joinPath ["doc", "html", "programming.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         , writerHTMLMathMethod = LaTeXMathML Nothing
         })

     mkHtml
       (joinPath ["doc", "src", "architecture.txt"])
       (joinPath ["doc", "html", "architecture.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         , writerHTMLMathMethod = LaTeXMathML Nothing
         })

     mkHtml
       (joinPath ["doc", "src", "assembly.txt"])
       (joinPath ["doc", "html", "assembly.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         , writerHTMLMathMethod = LaTeXMathML Nothing
         })

     mkHtml
       (joinPath ["doc", "src", "linking.txt"])
       (joinPath ["doc", "html", "linking.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         , writerHTMLMathMethod = LaTeXMathML Nothing
         })

     mkHtml
       (joinPath ["doc", "src", "execution.txt"])
       (joinPath ["doc", "html", "execution.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         , writerHTMLMathMethod = LaTeXMathML Nothing
         })

     mkHtml
       (joinPath ["doc", "src", "tutorial.txt"])
       (joinPath ["doc", "html", "tutorial.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         , writerHTMLMathMethod = LaTeXMathML Nothing
         })

     mkHtml
       (joinPath ["doc", "src", "colophon.txt"])
       (joinPath ["doc", "html", "colophon.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         , writerHTMLMathMethod = LaTeXMathML Nothing
         })

     mkHtml
       "README"
       (joinPath ["doc", "html", "README.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         })

     mkHtml
       "INSTALL"
       (joinPath ["doc", "html", "INSTALL.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         })

     mkHtml
       "LICENSE"
--       "dist/doc/html/Hydra/LICENSE.html"
       (joinPath ["doc", "html", "LICENSE.html"])
       (defaultWriterOptions
         { writerIncludeBefore = csslink
         , writerStandalone = True
         , writerTableOfContents = True
         })

------------------------------------------------------------------------
_______________________________________________
Haskell-Cafe mailing list
Haskell-Cafe <at> haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe

Gmane