Data-oriented design is basically the process of describing the function of a program in data - be it an XML material specification, runtime scripting, etc. Rather than making large complex functions that operate on dumb data, the goal is to move the intelligence to the data: The application becomes analogous to an interpreter, doing what the data says, albeit at a high level.
When this strategy is applied to software design, I have noticed that certain patterns of classes emerge. First, I tend to have pure-data classes that just store and manage some data (i.e. the Mesh class). These pure data classes can then be aggregated into larger, more complex data models, or operated on by functions or classes that act as simple operations with some object state (MeshRenderer, MeshAnimator).
If I had to pick the most important 'commandments' of software design I've developed, they'd be:
- Classes should in general only perform only one task or hold one type of data. Same goes for functions. This is the single responsibility principle. It keeps you from creating monolithic functions/classes that do 1001 things that produce hard to debug and unorganized code.
- Avoid dependencies between classes and modules wherever possible. This keeps the individual parts small and simple, producing easier to debug and more robust code. Changes in one module rarely effect another.
- Keep your code simple while providing maximum flexibility. This tends to result in a data-oriented design without even trying.
- Make your code as clearly legible as possible. This means good use of whitespace and indentation as well as using class and function names that read like nouns and phrases and are very clear about what they are doing, even without comments. Keep actual comments concise and precise, noting any special behavior, rather than generic Doxygen-style @param comments.