I typically separate things into separate projects along what I call reuse
boundaries.
If I see code that can be used in multiple projects then I always consider
making it an isolated project of its own. That way you can build it and test
it as an isolated unit then call that code form other projects as a library
without having to resort to copy-paste coding.
Another reason I run into quite often to separate things into projects
(aside the fact already brought up that it allows different people to work
on different areas of code in a group programming environment) as when you
have a case where you need explicit separation of code. I had a case
recently where I was building a drawing surface that allowed you to place
drawing objects on it and connect then, kind of like Visio.
- The drawing surface itself as one component all by itself because it was
only supposed to know about its own needs and data.
- The base classes that defined how drawing objects were to look/act like
was in another library/project since they did not care about the drawing
surface themselves, they just defined what a 'shape' was to look like and
how it was supposed to act at a very base level.
- I then have other libraries that defined my individual shapes.
The benefit here is that the drawing surface had a reference to the drawing
object library only to know how a drawing object at a very basic level was
to act. The other individual shape libraries had a reference to that same
base library so they had an idea how to act and what interfaces they HAD to
implement so the drawing surface could contain them. This structure allowed
me to create an explicitly week reference between the drawing surface and
the individual shapes. This means that I can create new shapes and they will
work on the same drawing surface without having to rebuild the drawing
surface component itself each time I add a new shape.