Talks

Micro Libraries FTW

This video was recorded on http://wrocloverb.com. You should follow us at https://twitter.com/wrocloverb. See you next year!

Piotr Solnica with MICRO LIBRARIES FTW

I'm dreaming about a ruby ecosystem that consists of plenty of awesome, kick-ass, small, focused, well-written, nicely documented, composable libraries. Micro-libraries. I want those libraries to work on all major ruby implementations. I want those libraries to use as little magic and monkey-patching as possible. I want to be able to compose bigger frameworks using those libraries. In this talk I will tell you WHY I want all those things and HOW we could achieve that.

wroc_love.rb 2014

00:00:12.879 Hello.
00:00:19.060 Thank you for joining me. I'm going to talk about micro libraries, but first, let's start with a quick note.
00:00:25.390 I want to thank Matt. My GPU in my laptop broke yesterday, so I bought a MacBook from Matt. Thank you! He saved my life.
00:00:41.210 So, who am I? Unsurprisingly, I'm a Ruby developer actively working on various open source Ruby libraries. You can find me on GitHub or follow me on Twitter.
00:00:51.980 This is one of the biggest open source projects I was working on recently, and I want to mention it because this talk is heavily based on my experience with this particular project.
00:01:07.369 Now, what's on the agenda? I'll start by explaining some major differences between big libraries and micro libraries. Then I'll talk a little about micro frameworks and demonstrate some example micro libraries that we already have. At the end, I want to introduce you to a new project called micro.rb, which I launched last weekend.
00:01:30.440 So, what are big libraries versus micro libraries? Here's a simple table showing four major differences.
00:01:46.729 First, big libraries solve many problems, whereas micro libraries focus on solving just one specific problem. This leads to the next point: big libraries are well-baked and have lots of lines of code, while micro libraries tend to have a very small amount of code.
00:02:35.240 The next difference is in their interfaces. Big libraries, since they support a lot of functionality, often have very wide interfaces that might even be confusing to use. In contrast, micro libraries have very focused, narrow interfaces that are easy to use and quite obvious.
00:02:50.420 Lastly, let's discuss the concept of churn. Big libraries tend to change a lot—churn represents how often code within a given library is modified. In contrast, small libraries don’t undergo frequent changes, especially after reaching a major version.
00:03:09.860 I want to talk a little bit about Ruby on Rails' influence on this topic, as I believe it’s closely related. First of all, Ruby developers love Rails, primarily because many of us began our journey with Ruby through Rails, myself included.
00:03:39.530 We learned Ruby via Rails, which is somewhat peculiar because we started with a very specific mindset—the Rails mindset. I think Rails has a tremendous impact on how we write Ruby code. There are three aspects of Rails and the styles it promotes, implicitly or explicitly.
00:04:07.100 First, Rails is in favor of larger libraries, consisting of just five libraries, all of which are gigantic. If you’ve ever looked into ActiveRecord or ActiveSupport, you’ll see they encompass thousands of lines of code, adding serious complexity.
00:04:51.830 Second, ActiveSupport promoted monkey patching in an extreme way, leading developers to monkey patch everything. Personally, I consider monkey patching an anti-pattern, and it should generally be avoided in libraries.
00:05:12.290 Finally, I’ve noticed a recent trend where people are hesitant to introduce new classes and objects, possibly because they’re accustomed to ActiveRecord, which handles too many responsibilities at once.
00:05:39.120 I've received numerous feature requests in my projects where users ask, 'How about adding this?' or 'What about this feature?' My response is often, 'No, it’s good as it is. We don't need extra features; they should be handled by a separate layer.' Users, however, are often confused, as Rails offers it all.
00:06:02.629 Lately, I’ve been thinking about our dependence on Rails. For the last few years, I’ve been discussing with people writing about the issues with Rails and proposing alternative methods of utilizing it.
00:06:34.410 I've concluded that it’s better to embrace the UNIX philosophy—a fundamental concept that encourages building simple programs that perform trivial tasks but combined can create powerful, useful tools.
00:06:48.810 I think we are missing many of these small, focused tools that we could use in conjunction to build high-level frameworks. This is why I believe micro libraries are invaluable.
00:07:14.810 Now, why would you consider building a micro library? There are three scenarios where building a micro library makes sense. The first is when you have complex functionality in an existing project that you anticipate needing in another project or multiple projects.
00:07:34.327 In such cases, it’s an excellent opportunity to extract, decouple, refactor, and clearly specify interfaces to create a micro library that can be reused.
00:07:59.819 The second use case is when you notice a pattern that you keep repeating across different parts of your codebase. This is a good opportunity to think about how to generalize, extract, and encapsulate that pattern into a small library.
00:08:18.580 The last use case, which is probably rare, is when you have a very specific problem you want to solve that can be addressed by a very focused library.
00:08:30.360 For example, if you're developing an ORM and need to generate SQL, you would want an SQL generator.
00:08:51.850 Now, let's shift focus to frameworks. I believe frameworks should be built on top of micro libraries. While building frameworks, I've noticed two main approaches: bottom-up and top-down.
00:09:06.690 Both methods have their challenges. Bottom-up is only beneficial when you truly understand the complexities involved, which doesn’t often happen.
00:09:26.040 Usually, there’s this experimental phase where you need to play with things and learn. This leads me to believe that the top-down approach is often more effective.
00:09:48.700 In the top-down approach, you start with a higher-level concept and work your way down, identifying what you need along the way.
00:09:59.450 However, I find that the top-down approach can often be misleading; it’s great in theory but has flaws in practice, especially in Ruby projects.
00:10:16.710 Many developers begin building immense frameworks while mixing together high-level concepts and core domain logic, which often results in disaster.
00:10:32.150 A prime example is Rails itself; it experienced considerable hurdles that required a complete rewrite.
00:10:50.180 So, when building a framework, you ought to focus on the high-level concerns, leveraging the underlying micro libraries while keeping the code simple and clean.
00:11:04.480 Obviously, there are challenges involved; I could give a whole talk just on that. One of the primary issues is managing dependencies.
00:11:23.040 In Ruby, we have RubyGems and Bundler, but they can be slow. From a developer's viewpoint, installing something or dealing with gem files and version specifications can get tedious.
00:11:50.150 When you have many dependencies and start encountering conflicts, you could end up in a situation where you are completely locked out because of a version conflict.
00:12:10.390 While conflicts can be resolved by adjusting version specifications, they are still incredibly annoying.
00:12:28.046 We also have something called meta gems, which are gems that depend on multiple other gems. When people install such a gem, they often see many other dependencies being installed.
00:12:49.230 I've seen users get overwhelmed, thinking they picked a lightweight library only to discover it installs several other libraries.
00:13:05.220 While dependencies can be problematic, I believe that having genuinely focused libraries that can work together is a better approach, even if it introduces some dependency challenges.
00:13:27.650 The biggest issue arises when frameworks depend on the same gem; when dependency hell strikes, it can cause significant complications.
00:13:44.880 I was considering how to tackle this; the most crucial step is being strict with semantic versioning. It's critical that conflicts between versions are managed accurately.
00:14:06.860 It's preferable to have a conflict rather than releasing library versions that install but do not function properly. Maintain your version numbers diligently.
00:14:29.639 Documentation is vital; please maintain proper changelogs. A simple note about breaking changes in changelogs can save a lot of developers time.
00:14:50.779 There are online services that can assist with this. For instance, Ruby Toolbox lets you see what other gems depend on your gem.
00:15:02.710 I’ve found it helpful to identify which of my projects are being depended on by others and engage with their maintainers.
00:15:16.509 Whenever I'm about to make breaking changes, I inform affected maintainers, which facilitates collaboration.
00:15:29.740 Another useful tool is Gemnasium, which shows the dependencies of your gem, making it easier to remain current with updates.
00:15:42.290 Let me share some example micro libraries that we have. Most of these were created while we worked on Ruby Object Mapper or were inspired by that project.
00:16:00.660 The first is 'Equalizer', a tiny gem that enables you to include a module, pass in the desired attributes, and gain equality methods along with a nice inspect method for free.
00:16:18.950 Another example is 'Anima', which is developed by Marcus. It leverages Equalizer internally, allowing you to create constructors that accept hashes while also providing equality methods.
00:16:30.919 This also includes the inspect method from Equalizer, showcasing how several libraries can work seamlessly together.
00:16:44.489 Objects in Virtus will utilize Equalizer under the hood, providing additional functionality for free, like equality methods and inspection.
00:16:56.910 So, concerning frameworks, I believe they should be constructed using small, focused components. For instance, Ruby Object Mapper is evolving into a framework.
00:17:14.140 Internally, it is shaping up to resemble a domain-specific language (DSL), and I've been emphasizing higher-level interfaces.
00:17:31.230 One significant challenge in data mapper libraries is managing data as it flows between the database and your objects.
00:17:48.130 When extracting data from the database, you must load it correctly into objects, then, when saving, it must be transformed back into a database-compatible representation.
00:18:07.080 Searching for a pure mapper library was essential, and I discovered that Morpher, developed by Marcus, has become the effective mapper for Ruby Object Mapper.
00:18:23.100 This is fantastic because Morpher elegantly handles data loading and dumping, allowing you to call just one method to execute these transformations.
00:18:41.080 If we were to resolve this within ROM, we would end up writing countless lines of code; instead, by relying on Morpher, we alleviate that complexity.
00:19:00.490 Morhp's transformers offer a clean solution to this, and with ease, we can call to reverse the transformation for data dumping.
00:19:18.510 This is a huge problem, and Morpher addresses it effectively, eliminating the need for excess complexity within my codebase.
00:19:35.890 Initially, while working on Ruby Object Mapper, we aspired to promote a development style that favors small, simplistically focused libraries.
00:19:50.340 I realized that using a data mapper implementation might not align with that ideal.
00:20:06.550 I wanted to establish a separate project to more directly promote those principles.
00:20:25.450 Hence, I stumbled across a website called microjas.com, and it inspired me to start micro.rb.
00:20:41.290 Micro.rb will eventually compile libraries that adhere to specific criteria which we are still defining.
00:20:58.880 The differences between big libraries and micro libraries that I previously mentioned will likely become foundational criteria for this site.
00:21:16.540 I want micro.rb to serve as a tool where everyone can find libraries that solve specific problems efficiently.
00:21:34.280 It should be easy to identify libraries that are stable and used in production, ensuring confidence in their selection.
00:21:50.470 Additionally, I want micro.rb to serve as a platform connecting maintainers with potential contributors, ensuring libraries stay well-maintained.
00:22:07.740 This initiative aims to promote the UNIX philosophy, supporting a development style centered around small, effective libraries.
00:22:23.200 I envision creating a new ecosystem filled with distinct, remarkable libraries that can seamlessly combine to create higher-level tools.
00:22:39.020 I want to advocate for frameworks built atop these libraries, like Ruby Object Mapper, as they represent a much better direction.
00:22:57.760 And that’s it! Thank you.
00:23:42.500 Thanks for the talk! Are there any questions?
00:23:52.710 Is there ever a situation where you would consider constructing a big library?
00:24:09.120 No, not at all.
00:24:26.100 So, you believe that all libraries can and should be split into small, focused libraries?
00:24:44.150 Yes, that's my current belief.
00:25:12.630 Do you believe Virtus is still a micro library, considering it initially aimed for single-focus attributes but has become more complex?
00:25:37.270 I think it has evolved into something larger; while it's still under 2,000 lines, its complexity has increased significantly.
00:25:54.650 Now, I would characterize it as a micro framework—tiny but still a framework.
00:26:16.670 Have you ever faced issues with this approach of separating into smaller concerns?
00:26:36.840 Yes, particularly in the early stages, while building projects simultaneously, we experienced pain during upgrades.
00:26:53.130 However, over time, we have started to benefit from that groundwork.
00:27:05.900 Do you think typically the UNIX philosophy works effectively within micro libraries in Ruby, considering the increased learning curve?
00:27:16.000 The costs are indeed higher, but I perceive frameworks as comprising higher-level libraries.
00:27:39.620 Micro libraries generally handle simpler tasks, so their use may not be apparent unless you dig into how a framework utilizes them.
00:27:59.030 Is ROM an essential part of your experience, or are you needing assistance in your projects?
00:28:10.870 How do you work when you invite help?
00:28:31.200 The process can be tricky. We operate ad hoc; there's no precisely organized roadmap.
00:28:55.080 If anyone would like to help, they should reach out on IRC or contact me through Twitter or email.
00:29:20.010 What are your thoughts on using micro libraries together to create your framework? How do you best make them cooperate?
00:29:57.080 I create wrappers particularly in Rails apps to interact with them, and I conduct integration tests to ensure everything works.
00:30:14.080 Do you believe we should use micro libraries directly or assemble them into a larger library?
00:30:30.440 It depends. If you need to use them directly, then do so, but it may be more convenient to build on existing frameworks too.
00:30:50.100 It essentially comes down to preference; you can write more code if you need to, but you have more control over what you’re implementing.
00:31:23.800 Does anyone have further questions?