36

How should I name my Haskell modules for a program, not a library, and organize them in a hierarchy?

I'm making a ray tracer called Luminosity. First I had these modules:

Vector Colour Intersect Trace Render Parse Export

Each module was fine on it's own, but I felt like this lacked organization.

First, I put every module under Luminosity, so for example Vector was now Luminosity.Vector (I assume this is standard for a haskell program?).

Then I thought: Vector and Colour are independent and could be reused, so they should be separated. But they're way too small to turn into libraries.

Where should they go? There is already (on hackage) a Data.Vector and Data.Colour, so should I put them there? Or will that cause confusion (even if I import them grouped with my other local imports)? If not there, should it be Luminosity.Data.Vector or Data.Luminosity.Vector? I'm pretty sure I've seen both used, although maybe I just happened to look at a project using a nonconventional structure.

I also have a simple TGA image exporter (Export) which can be independent from Luminosity. It appears the correct location would be Codec.Image.TGA, but again, should Luminosity be in there somewhere and if so, where?

It would be nice if Structure of a Haskell project or some other wiki explained this.

mk12
  • 25,873
  • 32
  • 98
  • 137
  • 2
    If you want to make reusable piece of code, package it in a library. The size doesn't matter. – Cat Plus Plus Jul 21 '12 at 19:06
  • 2
    Vis reusable modules for geometric primitives - with algebraic types, Vectors and Colours are so easy to define that for serious use a Haskeller would want to define their own rather than rely on another library. They are then in control of their representations and don't have to worry about dependency problems (API changes, author going missing, etc.) – stephen tetley Jul 22 '12 at 06:11

2 Answers2

21

Unless your program is really big, don't organize the modules in a hierarchy. Why not? Because although computers are good at hierarchy, people aren't. People are good at meaningful names. If you choose good names you can easily handle 150 modules in a flat name space.

I felt like [a flat name space] lacked organization.

Hierarchical organization is not an end in itself. To justify splitting modules up into a hierarchy, you need a reason. Good reasons tend to have to do with information hiding or reuse. When you bring in information hiding, you are halfway to a library design, and when you are talking about reuse, you are effectively building a library. To morph a big program into "smaller program plus library" is a good strategy for software evolution, but it looks like you're just starting, and your program isn't yet big enough to evolve that way.

These issues are largely independent of the programming language you are using. I recommend reading some of David Parnas's work on product lines and program families, and also Matthias Blume's underappreciated paper Hierarchical Modularity. These works will give you some more concrete ideas about when hierarchy starts to serve a purpose.

Norman Ramsey
  • 198,648
  • 61
  • 360
  • 533
  • 1
    This is an interesting perspective! I normally have at least *some* form of hierarchical organisation in my programs. What is your order-of-magnitude threshold for "really big"? – Chris Taylor Jul 21 '12 at 21:37
  • I sort of understand your argument, but I disagree with the idea that this is independent of the programming language. At least to avoid naming collisions, one level should be introduced (`Luminosity.*`)—I'm not sure if you count that as a hierarchy though. I wasn't really asking about pros and cons of hierarchy, I'm asking specifically about Haskell conventions. Maybe this is bikeshedding, but the Haskell `base` hierarchy (as well as those of packages on Hackage) seems much different and less simple than the conventions of, say, Java or Python. – mk12 Jul 22 '12 at 02:55
  • As for the flat vs. hierarchy discussion, my reasoning behind making a hierarchy for my 8-module program was this: about half of the modules had nothing to do with ray tracing. I can organize them appropriately in my file browser locally, but on GitHub they're all alphabetized. I thought it would make it easier for people to take it all in by grouping related modules. Which seems to be the exact opposite of what you're arguing. – mk12 Jul 22 '12 at 03:28
  • @ChrisTaylor: By my standards I've never worked on anything really big. But flat structure has worked well for me on projects of 10,000 to 50,000 lines of code, with maybe 80 to 150 modules. Maybe 100,000 lines is really big? – Norman Ramsey Jul 23 '12 at 00:08
  • 2
    @Mk12: this is quickly getting into discussion and not Q&A, but I see your impulse a little better. Many projects have a "sin bin" into which useful but not directly related stuff gets thrown. This is the stuff that is vaguely general-purpose but is not big enough or good enough to turn into a library. I usually call my sin bin `Util`. As for the `base` hierarchy, it is explicitly *library*, not *program*, so different rules apply. – Norman Ramsey Jul 23 '12 at 00:10
14

First of all I put every module under Luminosity

I think this was a good move. It clarifies to anyone that is reading the code that these modules were made specifically for the Luminosity project.

If you write a module with the intent of simulating or improving upon an existing library, or of filling a gap where you believe a particular generic library is missing, then in that rare case, drop the prefix and name it generically. For an example of this, see how the pipes package exports Control.Monad.Trans.Free, because the author was, for whatever reason, not satisfied with existing implementations of Free monads.

Then I thought, Vector and Colour are pretty much independent and could be reused, so they should be separated. But they're way to small to separate off into a library (125 and 42 lines respectively). Where should they go?

If you don't make a separate library, then probably leave them at Luminosity.Vector and Luminosity.Colour. If you do make separate libraries, then try emailing the target audience of those libraries and see how other people think these libraries should be named and categorized. Whether or not you split these out into separate libraries is entirely up to you and how much benefit you think these separate libraries might provide for other people.

Dan Burton
  • 53,238
  • 27
  • 117
  • 198
  • I accepted your answer because I think it helped the most and was specific for me, but I combined your, Norman's, and Stephen's (comment on the question) advice. I'll keep everything under `Luminosity.` like you said. I won't bother making libraries out of my tiny modules or dropping the prefix since as Stephen said, every program probably wants their own vectors and colours anyway. And I'll keep everything flat rather than introducing hierarchy underneath `Luminosity.` for the reasons Norman gave. – mk12 Jul 24 '12 at 21:17