MSModels

doc-chuck
Login

How to write a documentation that only Chuck Norris can understand ?

Obscure doc means good image

The more obscure the doc is, the more professional your lib will look. Surely if a user doesn't understand the doc, it's because there is a vast difference in skill between you and him. To make this difference more obvious on the internet, don't forget to sometimes post god-like uni-line answers (i.e., a line of code, without any explanation) on forums.

Obscure doc means less bugs

If the doc is obscure, no one will use the lib, so no one will test it, so no one will write bug reports. And even if someone is reckless enough to do so, you can always answer that the lib is not used "as intended" because this user is too stupid. No one know what's intended, but no one will ask for it.

Kill the GPL without legal thread

This is also a very powerful strategy to circumvent open-source license : If no one know how to use your lib, no one will use it without paying for your expertise. You can therefore use all GPL-like stuff without being bother by someone else actually using your work.

You're THE guy

As the only one able to use your lib is you, you're pretty sure that you'll be hired for a job when someone wants to use your lib.

Use opaque memory management function/pointer types, then don't document them

Always use raw pointers

References and smart pointers are for pussies, they clearly betray the developper atempt and make obvious the way memory should be managed.

Instead of using them, always use raw pointers. Such types never express your intention, and without a long look trough the sources it's impossible to know how they should be managed.

Even if it's hidden somewhere, you'll have to add memory management functions. To do so, make the code more obscure by abusing templates, dispersing the memory management functions across the code, and using wired manageres (that should be initialized and free in a wired way too).

Don't forget to use heterogeneous naming conventions.

//Always mix these functions
template <typename T> my_free(T);
tempalte <typename T> void free(magic_handle<T> &t);
void free(My_type &t);
void free_xxx(Xxx *x);
int  clear(void*);
MyManager::default_instance()->free(&X* x);

Always use confusing handles

C++ user will surely complain about not RAII type. So make them happy : flip a coin : tail use a RAII handle, head : use a handle that must be freed manually by a free function.

Then, for RAII handles mix various unclear way of defining ownership : add, parents, sons, move functions, managers, garbage collectors and delete_latter functions.

pro tip Duplicate the standard smart pointers functionality with custom handles. You will look cool.

Awesome pro tip Use the std naming conventions (like my_shared or my_unique) for your handles, but use an implementation that slightly differs from what the std lib does. It will be super confusing!

Pitfalls

The C++11 move semantic is a very clear and common way of making ownership clear, therefore never ever use it. This is also the case with the smart pointers in <memory> : every programmer know them, and there is already a ton of clear doc on the internet about how to use them. They will make your memory management politic so obvious that everyone will be able to understand it by looking at your .hpp file.

Never wrap C stuff in a RAII struture. Check your code, if something somewhere matches the following template : erase it. Looking for file that include <memory>, or uses std::shared_ptr or std::unique_ptr is a good start.

//Too easy. Don't do that.

#include <X.h>
struct X;        //from a C lib
X*   create_X(); //from a C lib
void free_X(X*); //from a C lib

#include <memory>
inline std::unique_ptr<X> mk_unique_X(){
  return std::unique_ptr<X>(create_X(),[](X*x){free_X(x);});
}

Write minimal examples

Text compaction comes before locality and clarity

As reading text on the internet cost time, and as bandwidth is very expensive, write the shortest example as possible.

To do so, you must break two rules : clarity (never ever write something that can be guessed), and locality (never write an information next to the place where this information is used).

Headers are for pussies

Repeating the #include <something.hpp> directive in all of your examples is very annoying for the user. It takes room and it allow to copy-paste your example as is. Instead prefer writing your include directive in the introduction of your documentation.

pro tip Write some general include directive in a general introduction, then write more specific ones at the beginning of each related sections.

Namespace prefix are for idiots

To save more text, always prefer writing using namesapace xxx; instead of prefixing every single things with xxx::. The user can anyway deduce the right namespace by trying every possible combination. By coding this way, you're sure that using your objects in a .hpp file will be nearly impossible. Certainly the best way to be GPL-compatible, while being the only one that can use the code.

pro tip Use many nested name-spaces. This rule perfectly mixes with the header definition guideline in the documentation, as nested namespace can be easily spread in introduction sections all over your doc.

pro tip Use names that collide. Collision must be rare enough for not messing up your examples, but frequent enough to annoy the user. To make this tip more awesome, don't forget to rarely collide with the std:: namespace.

Don't compile

If you write a full example that compiles, users will try to compile it. That's bad. They may use it to find bugs in your lib, or worse see that it doesn't compile. Compilable example will make you look idiot... But sadly user will always ask for example to compile. So here is how to make your life easier.

As we've seen before, always spread information : don't put headers, don't precise namespaces, uses obscure classes defined elsewhere in an other file or part of the doc.

Mix language

Try to mix as many languages as possible. To make your life easy, depends on lib/code that are easy to run on your specific version of your specific platform, but be sure that they won't work elsewhere. For that, use the most CPU specific assembler code you can find, and use old version of uncommon languages.

Never list dependencies

Never ever do a single zip archive that contains everything that's needed to compile an example. Instead, add numerous external dependencies, and add dependencies that require other dependencies.

Use dependencies on many binary libraries

Include dependencies can be obtain by reading your .hpp files and header only libs are too easy to install. This is not the case for link-time dependencies. The c++ mangling rules makes guessing the lib name from the missing function name very hard. Therefore, always depends on a lot of binary-only library.

To do so, you can replace recent standard implementation (like std::function) by an old external dependency (like boost::function) that has does the same job. An other option to increase dependencies is to include unused stuff like <windows.h> when you use portable frameworks like Qt or GTK.

pro tip Never precise version number of dependencies, and never put a direct downloaded link. For open source software : standalone source pack that aggregate all source code of all dependencies if totally forbidden.

Add other files that are hard to get

To make the user life harder, you can requires old versions of some input or configuration files that are now online in a hidden archive part of your website.

pro tip Make all your example code dependent on a "common.hpp" file. Such file must be hard to download, and must mix many things that are required to run a lot of different examples. It will therefore be very hard to extract a minimal code that do something.

Order matters

Make library in a way that order matters for linking them. Of course never ever write this order somewhere. Instead enforce cross-dependencies between the various libs.

If your lib is used as a monolithic thing, always cut it into sub-libs, and enforce dependencies between the sub-libs. This tip mixes well with version incompatibilities between sub-libs and specific order for linking them.

Use specific compilation tools

If you can build your lib with a common compiler, you will look like a noob. If a simple 3 lines makefile does the job, you sucks. Always use a custom complicated compilation procedure, and be sure that this procedure uses uncommon tools. In few words use numerous, platform specific, uncommon tools.

super awesome pro tip Uses the same uncommon platform specific tools to compile themselves, you will therefore build a perfect mind blowing loop, yeah so awesome! If you do so, don't forget to apply to the boost development team, they will definitely need you.

If your code is open source, never support MinGW and Linux compilers. If you do so, users will enable warning and sanitizer to compile your lib. If they find warnings in your code, they will write bugs reports. Morever, some clever users may use valgrind to check for memory errors in your code. You never do memory errors, so you must be sure that valgrind will never work.

Provide binaries that are not usable in practice

Always provide only binaries for the last version of MSVC. The debugger never works (no debugger, no bug!), and you'll need a computer with 10 time the CPU power of a mainframe to compile anything that uses templates, so you're sure that no one can use your lib.

Only provide support for the last version of Visual Studio. No one can afford it, and the ones who can will never use it anyway, at it's so slow that you have to wait at least one second per character for echoing them to the screen. Moreover, the IDE is so awkward that even linking with an external lib needs a special recipes that no one can guess.

There is a slight risk that the stars are correctly aligned. On such days, the Microsoft debugger may produce a report before crashing. Of course this is so rare that no one can understand such report. To be sure that you won't be treated like a noob if such thing happens, never ever provide the debug version of your binaries. This tip becomes awesome with undocumented memory management as the most clever users will not be able to use a debugger for understanding your memory politics.

Best pro tip ever If users complain, just write : "you're compiler is not supported, please use MSVC".

pro tip Mix MSVC major versions for releasing various parts of your lib. In particular publish one part of the lib for 2013 and one part of the lib for 2015 and be sure that most practical cases required both parts. Of course never ever tells which binary is for which version.

pro tip Make your .lib architecture dependent, for example tweak the compilation options to only generate pentium4 code.

pro tip Make your .lib dependent of a particular version of windows. If you have to choose one, choose windows 8. It looks cool and nobody uses it.

Use a lot of dll

As bandwidth is expensive, you can make your lib smaller by using dlls. And to make it smaller, uses a lot of external dlls. Never ever try to know if this dlls are on a vanilla install of any windows stystem. Instead just assume that, if they are on your laptop, they exist everywhere.

pro tip Microsoft has a lot of wired way to distribute dll : instead of just packing everything you need with your exe file, force the user to install various and mutually incompatible "Microsoft xxx redistributable".

In your code try to mix different MSCV redistributable version and add some dependencies to .net lib too. If you do so, even a user who perfectly know how to run a dll dependency crawler will not be able to do a standalone binary distribution

With this method and some luck you will have the side effect to make your program incompatible with Wine, so no one can use Linux to test it. (And you know Linux users are the worse users in the world, they always criticize everything).