Library
Library is described as “a collection of implementations of behavior, written in terms of a language, that has a well-defined interface by which the behavior is invoked.”
The principle
What does it mean? To understand libraries we need to go back to beginnings of libraries. One of the biggest issues back then was how complicated the code was. Since applications had to be written as a whole, when they got bigger and more advanced, the number of bugs drastically increased. In 1959 JOVIAL introduced a way to split an application into smaller parts. The new solution became a basis for what we now know as libraries.
The next big step was the implementation of so-called “Linux way” or a “KISS Rule” (KISS= Keep It Simple, Stupid). To fulfill the latter any module or library had to do one thing and do it well. Combining this with the “Divide and conquer” principle (in which every difficult problem can be split into multiple smaller problems, which are then independently solved) we get the current library system.
Examples
Let's say we want to use a database. In PHP it's quite simple. All we need to do is connect to a database, prepare the question we want to ask and get the answer.
This example of pseudocode shows how to do it:
$config = ... //load config
$query = ... //some query
$data = ... //data for this query
$conn = mysql_connect($config['server'], $config['user'], $config['password']);
if($conn === false)
throw new Exception('cannot connect to database');
$success = mysql_select_db($config['databse']);
if($success === false)
throw new Exception('cannot select database');
$queryString = $query;
foreach($data as $key => $value)
{
$queryString = str_replace(':'.$key, mysql_escape_string($value), $queryString);
}
$queryHandle = mysql_query($queryString, $conn);
if($queryHandle === false)
throw new Exception('query failed');
$result = mysql_fetch_assoc($queryHandle);
if($result === false)
throw new Exception('query failed');
Quite a bit of work, isn’t it? And now imagine that you have to do 5 versions of this code for various databases. It can get messy very quickly. And this method is already using a library (yes, mysql_* functions are functions provided by a library called php-mysql)!
Let's try to use a library called PDO:
$config = ... //load config
$query = ... //some query
$data = ... //data for this query
$pdo = new PDO($config['uri'], $config['user'], $config['password']);
$statement = $pdo->prepare($query);
if($statement === false)
throw new Exception('query failed');
if($statement->execute($data) === false)
throw new Exception('query failed');
$result = $statement->fetchAll(PDO::FETCH_ASSOC);
if($result === false)
throw new Exception('query failed');
We not only reduced the code size from 20 lines to only 12 but at the same time allowed other databases to be used. Why is this so powerful? Because PDO library is internally using a different library, which is using another library, which is… This chain means that when you write a blog you don’t need to worry about resolving database address to IP or preventing SQL injection. It's all done for you by the library, so you can create the blog you are working on - you just “do one thing and do it well”. That is the power of libraries.
Disadvantages
Just like every other solution in the world, libraries also have disadvantages. There are two main issues you can step upon. First is so called bug propagation, second library limitations.
Bug propagation
Let's assume we are working on a library that is going to be used to calculate map distances - I will call it B. It's using a calculation library that allows adding, subtracting, multiplying and dividing - it's going to be called A. Someone is also using our library on their website, which is marked as C. In this scenario website C depends on library B that depends on library A.
Now, what happens if library A has a bug? Let's assume that adding two numbers always results with a number increased by 1, so 1+3 = 5, 4+4 = 9, etc. It will end with library B also showing wrong distances, while website C will also be incorrect. What is described here is a bug propagation - a bug in dependency will cause a bug in dependent.
Now let's assume we fixed that issue by modifying library B to always subtract 1 after the calculation. But after some time a patch for Library A will come out that fixed the problem. Now our library is a source of problems because we are needlessly subtracting 1. This is called derivative bug propagation.
The longer the chain of dependencies, the bigger the issue. Multiple libraries on the path can have workarounds for bugs in their dependencies, which will cause new bugs and propagate them down the line.
Limitations
When using libraries, their internals are often hidden from you. This is done on purpose, so a library is kept in a known state. Because it can do a limited amount of things, it's easier to debug it by for example covering all possible actions a library can do with unit tests. But at the same time, you might need to do some small tweak on internals or get some information this library cannot give you. There are three ways of solving this problem:
- The first one is to just give up. If you are asking for something a library cannot do, then maybe you should not ask for it, or just use a different library. In most cases, this is the best idea, because the other solutions may cause some trouble.
- The second solution is “the advanced way”. If a library is of a good quality, it often has three modes in which it can work: simple, normal and advanced. A good example is a music library I used a few years ago. To play a song until the end you had to just call:
player.play("filename.ogg");
In normal mode you were able to add some extra parameters to it, such as this:
music = player.load("filename.ogg");
music.setVolume(0.75);
music.play();
sleep(10); //10 seconds
music.pause();
That library still gives you the ability to access the underlying backend library by doing something like this:
music = player.load("filename.ogg");
handle = music.getHandle();
call_system_function(handle);
Unfortunately, the advanced way is not that common, and many quickly made libraries don’t have more than one mode in which they can work. Therefore if you are choosing which library to use, check whether it has an “advanced mode”. Even if you don't need it now, you may in the future - it's always easier to make a change sooner than later.
- The last solution, which is both the worst and the most commonly used, is hacking. Many languages have some backdoors you can use to access library's internals. And with those you can do almost anything. Just remember, by using a library in a way that differs from its original purpose you'll just ask for bugs.
Framework
Framework is described as “an abstraction, in which software providing generic functionality can be selectively changed by additional user-written code, thus providing application-specific software”.
The principle
Let's analyze what that means. The first thing we should do is think about what “abstraction” means. Well, in programming it describes something that is half finished, when it's up to an end-user (or end-class) to fill the gaps to complete it. Another thing to note about “abstraction” is that it already contains information about what those gaps are and how they should be filled. Let's take an iterator as an example. Iterator is an abstraction that must have a way of getting current object and moving to next one. Similarly, a framework contains a list of rules that need to be fulfilled to make the finished product.
Second thing we should note about a framework is that it often combines libraries and “packages”. We already know what is a library, what about those “packages”? Each framework has its own name for those. In Laravel they are called “packages”, in Symfony “bundles”, in other frameworks they may have different names. The easiest way to understand packages is imagining them as reversed libraries, where API is provided not by the library, but by a framework. This has a few consequences:
- every package should instantly work in a specific framework,
- package made for one framework cannot be used in other frameworks,
- packages are often bound to specific versions of framework, since package API must exactly match framework API
If you look at this list, you may think that libraries are far superior to packages. Because of that it's a common practice to create packages as proxies to libraries and keep the functional code in the library itself. This way you will have advantages of both worlds.
Advantages
One of the biggest benefits of frameworks is an easiness of creating code. Let's use the previous example of the database to check out Laravel:
$users = DB::table('users')->whereName('Hubert')->get();
Yes, we just changed all this lines of code (and query itself) to a single line, making it incredibly simple to use databases. Everything related to handling errors and loading Eloquent (library used to manage the database) is done for you by the framework.
Another advantage of using frameworks is their great support for MVC pattern. The fact whether MVC is better or worse than Decorator (used by libraries), is a topic for completely different article.
Disadvantages
Like everything, frameworks also have disadvantages. The biggest one is, in fact, the principle itself. Since framework is an “abstraction”, it has a relatively limited amount of features you can make in “the correct way”. But it doesn’t mean it cannot be done in a "hacky way”.
For example, it's common in object oriented programming to give objects a toString function that will provide its human-readable text representation. If your program supports multiple languages, you will need access to translator. Problem is, you don’t have access to translator (or any other service) in Entities in Symfony.
Framework vs Library
Now that we know what frameworks and libraries are, let's compare them, and find out where and when they can be used.
Master - Slave
The first and the most important difference between framework and library is the master - slave model.
When using libraries you are the master. That means you are using the library and have control over its usage. You can create an object and destroy it, as well as manipulate it (based on libraries’ API).
On the other hand, framework is using your code, so it works as the master. That means you don’t have control over what will happen and when, which is the responsibility of framework. The advantage is that you have less things to worry about, but you also have less control over what can be done. As I already mentioned, frameworks often tie your hands and prevent you from doing both stupid and useful things.
Flow of commands
In libraries your code is calling a function and gets a response in return. On the other hand, framework is calling your functions and you are returning responses. This has a tremendous impact on debugging. Since application flow is independent of programmer, it's impossible to make breakpoint-based debugging, nor follow the flow of data to find issue. The only solution is to use stacktraces and tools provided to you by the framework itself, while in libraries you can just look at data that goes in and comes out of functions to find source of problems.
Core of an application
One of the biggest decisions you have to make is which core for your application you want to pick. You can either pick one of the existing frameworks, or do it from the scratch. Depending on how complicated your project is, I would suggest getting the more fluent solution the more complex it gets. Therefore for a simple project you should pick a framework that fits your problem best, such as Symfony (because it has a lot of premade components). For more complicated ones, on the other hand, I would suggest going with more configurable frameworks (eg. Laravel) or even making code by hand, just to keep a good control of project.
Divide and rule
As I mentioned before, libraries are based on “divide and rule” principle, but packages used in frameworks can also base on it. Dividing big projects into smaller parts will make it much easier to control while it grows. That’s something you should consider when choosing a framework. When it (or its packages) has limited reusability (like eg. in TextPattern) it's best to avoid using it for bigger projects.
Final verdict
If you want me to choose between framework and library, you will be disappointed. Each solution has its pros and cons. But for achieving the best results you should combine those two solutions. Use and write libraries for each small thing your project does, such as ‘shop’, ‘search engine’ or ‘file management’, create proxy packages for them and use those packages in your favorite framework.
This way you will get good code quality, speed, reusability and control (advantages of libraries), as well as faster programming, and support from the community (advantages of frameworks).
Navigate the changing IT landscape
Some highlighted content that we want to draw attention to to link to our other resources. It usually contains a link .