HydraNode Core Documentation
HydraNode Core - Modular Peer-to-peer client framework
- Date:
- August 2004
- Author:
- Alo Sarv <madcat_ (at) users (dot) sourceforge (dot) net>
As is known, programmers greatest enemy is second programmer. During maintainance phase of a codebase, it is very easy to make the codebase into
spaghetty code. In order to prevent that, I have attempted to write the initial implementation as safely as possible to keep the codebase from falling apart as soon as tens of maintainers jump into it. Here are some things you should keep in mind:
- Coding Standard. I have used a very strict coding / documenting style in the codebase, and I'd prefer if it stayed that way. It is very important to keep the style same all over the codebase, as well as to keep documentation up to date. So if you modify a function, verify that the function's documentation reflects the new behaviour (do so even during trivial changes). Likewise, most files have "overview" documentation section at the top (headers). Review that on regular basis to keep that up to date. Now all this might sound very time-consuming and boring, but trust me - it pays off in long-term. I know you hate documenting, I did too until I had to maintain 100'000-line codebase with absolutely no documentation.
Follow the coding standard rules. Fully document all your code. Keep the documentation up to date. - Objects Decoupling. I have went through long sleepless nights in order to design the subsystems so that they would be decoupled maximally from each other. Systems communicate with each other at VERY MINIMAL base. Contained objects DO NOT know about the containers (e.g. MetaData and MetaDb, SharedFile and FilesList). The order of class declarations in headers reflects that idea - contained classes are declared prior to containers, so there won't be any chances they could 'accidentally' call container's functions (this last one applies only to inline functions in headers tho, you could still call the Container's functions in source files). If you really need to pass information from Containable to Container, use event tables (as I have done with MetaData and MetaDb). In short - if you REALLY need to pass messages over systems which, by common sense, shouldn't be aware of each other's existance, use event tables. They are the hammer of decoupling. Use them!
Do not couple together objects that are not supposed to know about each other! - Destructors. No, you can't do things in destructors. The reason for that is that most top-level container classes are Singletons and get destroyed during application shutdown AFTER exiting from main(). And the order of destruction is undefined, so you CANNOT rely that any other systems are still up and running if you are in some destructor - it may be the application shutting down, and the other subsystems are already down.
Do not do anything except cleanup in destructors. - Testing Apps. Nearly each and every class and subsystem should have a corresponding test application, located in tests/ subdir, which tests the classes' or subsystems features and verifies it's integrity. These tests should immediately fail as soon as the target behaves differently than it should. ALWAYS run the corresponding tests after modifying the contents of a class or subsystem, no matter how trivial the change may sound. Also, when new bugs are found in subsystems, the FIRST step should be to update the corresponding test case to detect this bug, and only after that the bug itself be addressed. This ensures that codebase stays operational during maintainance, bugs mostly don't even make it to CVS, and old bugs do not return. Only exception here is cross-platform issues - not all developers have access to all supported platforms, so it's usually forgivable if the tests work on developer's platform, but fail on some other platform. But don't make this your habit - this means someone else must fix your broken code, and that some else isn't going to be happy about it.
Regularly regress-test your code. Write regress-tests for all new classes/subsystems. Keep regress-tests up-to-date with the codebase.