Libraries: we use them all the time. A library is packaged code that developers can use in their projects, which invariably saves work and prevents reinventing the wheel. Having reusable packages, either open or closed-source, is better than rebuilding the same feature, or manually copying and pasting from past projects.
But other than packaged code, what is a library exactly? With a few exceptions, a library should always be one file, or several in a single folder. Its code should be maintained separately and should remain as-is when implementing it in your project. A library should allow you to set project-specific configuration and/or behavior. Think of it as a USB-device that only allows communication through the USB port. Some devices, such as mice and keyboards, allow configuration through an interface provided with or by the device.
Why Build a Library?
First and foremost, libraries make the reuse of existing code very convenient. You don’t have to dig up an old project and copy some files, you just pull the library in. This also fragments your application, keeping the application codebase smaller and making it easier to maintain.
Any code that makes achieving a certain goal easier and which can be reused, like an abstraction, is a candidate to be bundled into a library. An interesting example is jQuery. Although jQuery’s API is considerably more than a simplified DOM API, it meant a lot a few years ago, when cross-browser DOM manipulation was rather difficult.
If an open-source project becomes popular and more developers use it, it’s likely people will join in and help with that project by submitting issues or contributing to the code base. Either way, it will benefit the library and all the projects depending on it.
A popular open-source project can also lead to great opportunities. A company may be impressed by the quality of your work and offer you a job. Maybe a company will ask you to help integrate your project into their application. After all, no one knows your library better than you.
For many it’s merely a hobby—enjoying writing code, helping others, and learning and growing in the process. You can push your limits and try new things.
Scope and Goals
Before writing the first line of code, it should be clear what the purpose of your library is—you have to set goals. With them, you can maintain focus on what problem you hope to solve with your library. Keep in mind that your library should be easier to use and to remember than the problem in its raw form. The simpler the API, the easier it will be for users to learn to use your library. To quote the Unix philosophy:
Do One Thing and Do It Well
Ask yourself: What problem does your library solve? How do you intend to solve it? Will you write everything yourself, or can you utilize someone else’s library?
No matter the size of the library, try to make a roadmap. List every feature you want, then scrap as many as you can until you have a tiny, but functional library, much like a minimum viable product. That will be your first release. From there, you can create milestones for every new feature. Essentially, you’re breaking up your project into bite-size chunks, making every feature more of an accomplishment and more enjoyable. Believe me, this will keep you sane.
Personally, I really like to approach my library from the perspective of the end user. You could name it user-centric design. In essence, you are creating an outline of your library, hopefully giving it more thought and making it more convenient for whoever chooses to use it. At the same time you get to think about which aspects should be customizable, something discussed later in this article.
The ultimate API quality test is to eat your own dog food, to use your library in your own projects. Try to substitute application code with your library, and see if it covers all the features you desire. Try to keep the library as bare as possible, while keeping it flexible enough to make it work for their edge-cases too, through customization (as described later in this article).
Here’s an example of what the implementation, or outline of a User-Agent string library could look like:
// Start with empty UserAgent string var userAgent = new UserAgent; // Create and add first product: EvilCorpBrowser/1.2 (X11; Linux; en-us) var application = new UserAgent.Product('EvilCorpBrowser', '1.2'); application.setComment('X11', 'Linux', 'en-us'); userAgent.addProduct(application); // Create and add second product: Blink/20420101 var engine = new UserAgent.Product('Blink', '20420101'); userAgent.addProduct(engine); // EvilCorpBrowser/1.2 (X11; Linux; en-us) Blink/20420101 userAgent.toString(); // Make some more changes to engine product engine.setComment('Hello World'); // EvilCorpBrowser/1.2 (X11; Linux; en-us) Blink/20420101 (Hello World) userAgent.toString();
Depending on the complexity of your library, you may also want to give some thought to structuring. Utilizing design patterns is a great way to structure your library, or even to overcome some technical problems. It also reduces the risk of refactoring large parts when adding new features.