I'm writing a Java library that has a simple interface, but a lot going on behind the scenes. In order to keep the API surface small, I've kept the library as one large package (so that I can make most classes package protected). Now that the library has grown, it's become a little difficult to find the class you're looking for.
Is there any way to visually organize a lot of classes in the same package?
I know that in general, creating a new directory also creates a new package. Is there any way around that? Is it at all possible to have multiple directories that are all in the same package?
If not, I'm also open to any creative ways to visually organize the classes (I've considered prepending class names with the "package" it would be in, but I don't think that helps much).
If there are any solutions involving some sort of IDE tags, that would be acceptable too (we use IntelliJ).
Thanks!
Related
I'm trying to learn some basics of Java and Spring. Recently I came across some beginner project and one of the first steps was to create a Spring Initializr thanks to its website, where everything is clear to me. The next step was to create a basic package structure in the project: model, controller, repository, config, service.
Could someone explain me what exactly is meant by creating these packages after creating a new project? I tried to look up the information myself, but unfortunately I couldn't find an answer anywhere.
I will start by recommending reading about Packages in Java.
In a nutshell, packages are folders. They are used for storing (mainly) classes, but other entities can be stored in packages as well. For example, text files, pictures, etc. In Java, there is no hard set rule that state that only classes must be stored in packages. That said, this is typically not the way projects are structured.
One of the most important functions of packages is to provide namespace for classes. Consider two classes named Table. One is a table containing data and the other is a table used to put stuff on top of; for example a dining table. This means that Table will have to different meanings. Operating Systems will not allow for two files with the same name to exist in the same folder. Therefore, you need to put them in two folders (packages). In the code, you can break ambiguity by declaring the objects using the class' fully-qualified name. For example,
myproject.furniture.Table diningTable = new myproject.furniture.Table();
myproject.data.Table dataTable = new myproject.data.Table dataTable();
There is also access protection with packages by using default access modifier (no modifier). For example:
package myproject
class PackagePrivateClass {
// class contents omitted
}
Notice that this class is not public. In Java, this means that this class is visible to other classes in the same package only. Not even classes in sub-packages will have access.
In summary, packages provide namespace, physical organization, and access protection.
The second thing you should be familiarized with is the best practices with regards to naming your packages. Organizations tend to have packages structured with the domain first, then the main system the code is part of, then subsystems, etc. Before providing examples, here is an article about Package Naming from Oracle.
java.awt => Contains all of the classes for creating user interfaces and for painting graphics and images. AWT stands for Abstract Window Toolkit
When you see the package name, it gives developers and idea what type of classes can be found inside. This will help looking for functions when you are not familiarized with the API (which in turn will help you learning the API much faster). Imagine how hard would be to learn Java if all classes were in the same folder. Imagine how hard will be to figure out what the project does if meaningful names are not used. In the example above, it is kind of easy to figure how what to expect out of classes in the java.awt package.
I was hoping to give you more examples, but I am out of time. Maybe later I will return and write more about this.
Package is nothing but a group of classes. You want to categorize your classes basis their respective purposes. If it's just for self-learning, your package structure should be like
org.novak.sample.service.*
This package should contain all Services, not anything else.
So I have a Java application I will be releasing to one of my communities for a price. The app is just about complete and ready to be obfuscated but the problem is;
I found that when I add the Jar to another project in Eclipse you can instantiate classes externally and use my program as an external library to make scripts outside of my program. This is not what I'm wanting to achieve here... I'm self taught so I have grey areas of knowledge as I haven't learned formally, but I'm pretty experienced in Java still... I've tried googling it and nothings coming up, maybe I'm not phrasing it correctly. But if I could get some help it would be appreciated.
Here is my structure of my packages:
src.com
Contains main class
src.com.scripts
Contains Abstract Script class
src.com.scripts.impl
Contains the actual scripts that extend the abstract Script class
What I've tried doing:
I removed the public Identifier from the Abstract Script class but then it isn't visible to the main class to call it from as it is in the package before. So how can I go about this when my project is sorted in packages and they all need to access eachother?
There is no solution.
If people want to reverse engineer your code, they will. There is nothing you can do to change that. public/private are essentially meaningless beyond helping you write good portable code.
That being said, Java is generally much easier to reverse engineer and make bindings to than other languages. Java doesn't inline functions and unless told otherwise, it will even leave all of your class and method names intact. If you had used a language like C, the optimized binary would be a bigger pain to work with, but the result would still be the same.
Just obfuscate the jar and call it a day. Manually changing how you write your code is more harmful to you than it is to them.
As projects that I'm working on grow larger and larger, I'm starting to be pretty unsure about dividing classes into packages. Suppose the project has a lot of layers and in these layers are interfaces and implementation and even more sublayers (components). I always end up with a lot of packages which starts to be little confusing.
So I want to know other people's approaches to working with packages. Do you prefer to have a lot of packages with few classes or few packages with a lot of classes? Do you prefer to separate implementations from interfaces? And so on... In general your daily habits of using packages and pros/cons of your approach.
Thank you for your posts.
Packages are meant to help you find things.
If they make it more confusing than it is, you're not doing something quite right. If the package structure isn't intuitive, it can actually be harder to find classes than in a flat structure.
There are two basic schools of organising classes into packages as far as I know:
Organising by module first. Here your higher level packages are different modules of the system and you might split it further by function.
Organising by function. Here you organise by function first (e.g. all controller classes in one package, all your data containers in another and so on) and optionally subdivide it by module.
There are pros and cons for both systems, I find them roughlty equal, although I prefer the module approach slightly.
The really important thing is though to follow one system and don't mix it with the other. Don't shoehorn classes into packages they don't belong to and don't be afraid to create a new package if your new class doesn't seem to belong to any of your existing ones.
If a package seems to have grown too large, you might want to split it. But the decision of whether a package should be split or not should be made on whether there is a clear conceptual divide between classes therein and not on numbers. A package with a single class is just as good as a package with thirty classes if it's obvious why they're there.
As for separating interfaces and implementations, first off, I'd probably question the need for them. Ever so often I come across interfaces with only one reasonable implementation, which makes me question their reason to exist. (Sometimes there is a good reason, but often there isn't.)
But if you have multiple implementations for a given interface, then yes, I'd separate them. The interface would be com.foo.Bar and the implementations would be something like com.foo.bars.CrowBar, com.foo.bars.TaskBar for example. Obviously, if your implementations belong to different modules, then you would change it to com.foo.moduleX.bars.CrowBar or com.foo.bars.moduleX.CrowBar, depending on which system you're following.
Re-reading all this, it does sound kind of complicated, but probably the first sentence is the most important: don't follow packaging principles blindly, packages should help you find classes, not hinder you.
I prefer to limit the scope of my classes and methods to private or package protected wherever possible (so they don't clutter Eclipse's autocomplete:) which automatically means that packages can contain quite a few classes.
I do prefer to separate business data objects (DAO's) from their repositories/retrieval services, which are separated from business logic objects and views.
Sets of related functionality with no cross dependencies tend to go in their own artifact as I tend to reuse logic. Especially handy when you start playing with OSGi and independent services.
One thing is important, the publicly exported interface (public interfaces, enums and classes) need to be somewhat related so the package documentation shows some cohesion.
For our assignment we need to write code for a neural network. The way I planned to do it was to write a Node class, which is a node within the network; a Layer class, which is a layer of nodes and a NeuralNet class, which is a network of layers.
I'm having a lot of trouble understanding the way Java is designed to work for imports. To me it seems that it should be a simple matter to include my Node class in my Layer class, and my Layer class in my NeuralNet class, however Java doesn't like importing from the default package.
What I have read suggests that anything you import needs to be in a package and packages have their own subdirectory. Because of the way I plan to structure my classes, this leaves me with what seems to me, an unwieldy and unnecessarily complex directory structure ie.
neuralpkg.layerpkg.nodepkg.Node
Can someone explain to me whether this is the only way to implement the structure that I want or whether there is some much, much simpler way that I've missed?
For what its worth I'd have no trouble writing this in C/C++, but attempting to import in a similar style has only given me heartache.
You don't need to layer the package like neuralpkg.layerpkg.nodepkg, where "neural", "layer", and "node" are subpackages for the respective classes.
You can simply create a package named "ben" and put all of your classes in there. So within your source directory you'd have a layout like:
--/ben
----Layer.java
----NeuralNetwork.java
----Node.java
Each class definition should then start with the line package ben;.
Classes in the same package don't need to import each other.
It's more like this:
Make a directory called src. This is the root under which all java files will go. Underneath it, make a series of directories called
com->ben->neural or some such. Put all your java source files in the neural folder.
Also, what IDE are you using? Score yourself Netbeans, Eclipse, or the free version of IntelliJ. Java needs a good IDE. When you create a new class, the IDE will do the package statement for you and help immensely with the imports.
Think of packages in Java like namespaces in C++. From what it sounds, it seems like you want everything in the same namespace. The default package can sort of be thought of as unnamed namespaces (I think).
What you should do is just create a simple package com.class.hw01 for example. And put all your classes in there. That way you don't even have to import anything, you can just declare/use your classes just like in C++ if they were in the same namespace.
I recently looked at a Java application which had a very fine-grained package structure. Many packages only contained one or two classes and many sub packages. Also many packages contained more sub packages than actual classes.
Is this a good or a bad thing?
IMO, it is a bad thing, though not a real show-stopper in terms of maintainability.
The disadvantages are that it makes classes harder to find, and that it makes the package names more verbose. The former applies more when you are not using an IDE.
It could be argued that it helps modularization in conjunction with "package private" scoping. But conversely, you could also argue that over-packagization actually does the opposite; i.e. forcing you to use public where you wouldn't have had to if you'd been less fine-grained / pedantic.
The actual number of types that end up in one particular package is not that important. It is how you arrive at your package structure.
Things like abstraction ("what" instead of "how", essentially "public" API), coupling (the degree of how dependent a package is on other packages) and cohesion (how interrelated is the functionality in one package) are more important.
Some guidelines for package design (mostly from Uncle Bob) are for example:
Packages should form reusable and releasable modules
Packages should be focussed for good reusability
Avoid cyclic dependencies between packages
Packages should depend only on packages that change less often
The abstraction of a package should be in proportion to how often it changes
Do not try to flesh out an entire package structure from scratch (You Are Not Going To Need It). Instead let it evolve and refactor often. Look at the import section of your Java sources for inspiration on moving types around. Don't be distracted by packages that contain only one or a few types.
I think finer grained package structure is a good thing. The main reason is it can help minimize your dependencies. But be careful... if you break things up too much that actually belong together, you will end up with circular dependencies!
As a rule of thumb, I usually have an interface (or group of related interfaces) in a package. And in subpackages I will have implementations of those interfaces (instead of having all the implementations in the same package). That way a client can just depend on the interface and implementation of interest... and not all the other stuff they don't need.
Hope this helps.
It is subjective, of course, but I generally prefer to decide my packages in a way they would contain at least 3-4 classes, but not more than about 13-15. It makes understanding better, while not cluttering the project. For others it might be different, though.
In case a package grows more than 13-15 classes, a subpackage is asking to emerge.
A package is a unit of encapsulation.
Ideally, it exposes a public API via interface(s) and hides implementation detail in package private classes.
The size of the package is therefore the number of classes needed to implement the public API.
There is also the magical number 7 +/- 2. Within physiological circles it has been shown that this is a basic limit on our ability to comprehend a given set of things. How much we can keep in short term memory and process at the same time before our brains need to start swapping. It is not a bad rule of thumb I've found when coding, ie once a package starts getting bigger than 10 classes it is time to think seriously about splitting it up, but below 5 packages it is really not worth it. Also applies well to things like menu organisation. See Millers paper, or google.
When writing from scratch my way is to begin all classes in the root package (com.example.app1). When there is a certain amount of interrelated classes that "do a whole thing" is time to create a package. After some time developing helper classes may go to a generic package (ex. com.example.app1.misc, com.example.app1.utils) to unload the root package.
So i try to keep clean the root package.
Fine-grain is not bad but as other said often refactoring produce a compact package structure.