But what are packages?

To understand what packages are, we should first understand what kind of files may exist on a system, and how we can make our own program. I'm not going to make a complicated program, just the basics to act as an example.

Paths

Before we begin, we must understand how paths work. There are mainly two ways to specify a location on your system: through absolute paths, and relative paths. An absolute path will always specify a location with absolute certainty, no matter where you're currently located. A relative path is... relative to your current location.

Absolute paths in Linux always start with a /, which is the start of all places on Unix-like systems. We often call this directory the root filesystem, the root mountpoint, or just root. Each consequent forward slash specifies a subdirectory of the previous location. As an example, /home/mazunki/ is two directories deep from root.

There are two pseudo-directories which exist in all directories, namely . and ..
That's correct: dot, and dot-dot. They are just concepts, and don't exist on disk. The single dot represents the current directory. The double dot represents the parent directory (aka the directory where the given directory is located in). /home/mazunki/.. represents the same thing as /home, and cd ./ would change your directory... into exactly where you're currently at.

PATH is an environmental variable which specifies where your shell can find commands. Try to echo ${PATH} in your shell, and see how it looks. You will see it's just a long text of different locations, separated by a single colon, aka the : character.

For funsies, try to ls some of these locations.

Executable files

Suppose you have written a text file including the contents print("Hello world"), and nothing else. You may know this is valid Python code, meaning you can run this code through the python interpreter. You open up your terminal, and type python3 my_program.py. It prints Hello world, just as you expected.

Since we now have a valid Python program, why don't we tell the file itself that it's a valid Python program? That's what a shebang is. Shebangs need to know where the program running our code is located, instead of the name of the program. You may know you can see the location for the python binary by running which python3, and it'll probably respond with /usr/bin/python3.

Knowing this, we can modify our program to include a shebang. Your program will now have two lines: #!/usr/bin/python3 on top, and print("Hello world") on the second line. This means that you no longer need to specify python as our interpreter, and can run our program directly!

We try that, typing ./my_program.py into our shell, only to see it complain about permissions! That's because our system protects us from accidents and malicious code. We need to tell our system the file should be executable. To do this, we can simply run chmod +x my_program after creating our file, which will change the file's permissions. Now, the same command will work :)

Sharing our program!

Now that you have a very cool working program, you want to share it to your friends. You do the big-brain movement, send them a pastebin link, and tell them to just download it. They don't know anything about what you just learned. What should they do? You start telling them: just copy the code into a text editor, save it on disk, ... they fall asleep cuz they don't care that much.

Because you really want them to see your cool program, you figure you could just give them a one-liner command to run in their shell. After some fiddling, you realize you can upload your program to a service such as 0x0.st, which they can just curl.

This approach works! It also stinks.

Dependencies

After a few weeks your program grew a bit more, and you now need to use a bunch of modules such as numpy and matplotlib (don't worry about what these are) to make your program do what you want. You do the same as you did above, and your friend complains: «It tells me i'm missing some modules». You tell them to just install them. They don't know how. You give them /yet/ another one-liner to install them. Agh, it didn't work because of some conflict on their system. You cry, they cry. You hug. You decide to eat pizza instead.

They could certainly figure out how to fix the conflicts on their system, but this is bad. End users shouldn't touch any system-wide files, because other applications may be needing those same files. Are you willing to break those other applications just to show them something? How do you recover the original files after you're done?

This short story is the essence of how all programs works. But to install firefox, you simply had to apt install firefox. What if your friend could also do that? Welcome: package managers

Package managers

The job of a package manager is to know what is installed on your system, and allow the (privileged) user to install stuff on their computer. It is also its responsibility to make sure the programs actually work, with all its necessary dependencies.

Package managers are not magical. They need instructions. They need to know what your program is called, which version it is, where to find the corresponding files, which dependencies it depends on, and how to actually install your application. The collection of all these rules and instructions is what we call a package.

Different distros use different package managers, and different package managers will require the packages to be specified in a different format. This is a bit annoying, but in most cases it's fine to just prepare a single package for a single distro. Other maintainers using other distros which desire your program may just port it. It's generally quite easy to port from one format to another.

So you read up on how to create a .deb package, but how do you distribute it? That's what repositories are. A repository is just a distributor of packages. It's often hard to push your own package to «official» repositories, reason of which generally boils down to the process of verifying your software is not malicious. This is why third-party repositories exist. You can make your own repository, and ask your friend to just add it to their system first.

Now, instead, you can just tell your friend to run the following:

add-apt-repository 'deb https://deb.mazunki.tech stable'
apt update
apt install my_package

Congratulations, you're now a responsible citizen! It will even update your application automatically as you release new versions!

Using system-wide locations

Now that you've learned how to use package managers, you should learn to use the proper conventions used in the FHS. Place your program files in the proper locations, and give them reasonable names.

We mentioned the PATH variable earlier. If you place your program under any of these locations, your program will become available to the user without having to specify the full path to your application. That's a desirable quality.

You can call the entry command for your program my_program instead of my_program.py, and place it under /usr/bin/ instead. Since the package manager will verify there is no file conflicts between different packages, it's perfectly safe :) That said, you probably don't want to call your program firefox, since then the user would need to choose which firefox file they want to keep.