Get Even More Visitors To Your Blog, Upgrade To A Business Listing >>

The most underused pattern in Ruby

… and check why 5600+ Rails engineers read also this Recently one of the RailsEventStore users posted an issue that one wanted to use RES on a Postgres database with Postgis extension. Migration generator used to setup tables for events and streams was failing with UnsupportedAdapter error.In RailsEventStore we supported to date PostgreSQL, MySQL2 and SQLite adapters representing given database engines. But if you want to make use of mentioned PostGIS extension, you need install additional activerecord-postgis-adapter and set adapter: postgis in database.yml. Our Code relied on value returned by:I thought — Ok, that’s an easy fix, PostGIS is just an extension, we need to treat it like Postgres internally when generating migration. Same data types should be allowed. This easy fix required me to change 8 files (4 with implementation and 4 with tests). Something is not ok here — I thought. So let’s look through each of them:I had to add postgis to the list of SUPPORTED_ADAPTERS in VerifyAdapter classThen I had to extend case statement in ForeignKeyOnEventIdMigrationGenerator#each_migration methodSame goes for Rails version of migration generatorWhat is important, both of the migrators used VerifyAdapter class (and two other migrators too).TemplateDirectory class also suffered from primitive obsession and it was used by all of the migrators too.There was also one more place — VerifyDataTypeForAdapter which was composed of VerifyAdapter, adding verification of data types available to given database engine.Here we go again, another checks of string values, but in a more specific context:Having all this within a dedicated Value Object would allow reducing number of decision trees in the code, checking the same primitives on and on.Something like: After few iterations we ended up with the implementation below:DatabaseAdadpter acts like a parent class to all the specific adapters.Specific adapters contain lists of supported_data_types to access those by client classes and render informative error messages if selected data is not supported by given database engine.They can also tell how the template_directory is named for given adapter.We have a single entry with DatabaseAdapter.from_string which accepts adapter_name and optionally data_type which are both validated when creating an instance of specific adapter.Three utility classes could be removed:Four classes and two rake tasks were simplified since the Value Object carriers all the necessary information for them to proceed:We could reduce branching and remove numerous private methods in those.The tests of above classes simplified a lot and are now focused on core responsibilities of the classes rather than checking which data types are compatible with given adapter.Soon, there will be new default MySQL adapter in Rails 7.1 called Trilogy. It would be cool to cover this case already. The only thing which we had to do in this case, was to change one line of code and add single line of test — since we already owned a good abstraction:Trilogy is an adapter for MySQL, there’s no difference from our perspective, we want to treat it as such.If you’re curious on the full process, here’s the PR with the introduction of DatabaseAdapter value object. The code is 100% covered with mutation testing thanks to mutant. I believe that Value Object is a totally underused pattern in Ruby ecosystem. That’s why I wanted to provide yet another example which differs from typical Money one you usually see.It’s a great tool to reduce complexity of your code by removing unnecessary or repeatable branching.



This post first appeared on VedVyas Articles, please read the originial post: here

Share the post

The most underused pattern in Ruby

×

Subscribe to Vedvyas Articles

Get updates delivered right to your inbox!

Thank you for your subscription

×