-
See this

First pieces of a dashboard for Tryve. Check it out http://www.tryveapp.com.
-
4 Ways to get your Rails app slim and outsourceable - 1. part
Rails are great! They give you powerful tools to keep high productivity, which is so important for every startup competing with massive amount of other companies. Engineers have to hurry to build comprehensive feature sets to satisfy all the stakeholders which often ends up with pretty complex monolithic application.
Its valid way.
You have to hurry and there is no time for crafting perfect code as we dont know yet it would pay of. Things would change when your product gets stable, team grows and you search for ways to keep that high speed of development.
Natural outcome might be decision to split development into multiple projects in dev team, or even outsource specific components offshore.
Convey’s law
Melvin Conway in 1968 introduced the idea of so called “Conway law”:
Organizations which design systems are constrained to produce designs which are copies of the communication structures of these organizations.
This basically tells that architecture of your team correlates with architecture of your software. If you would like to split your team, you have to split your software as well.
Luckily, there is quite a few ways how to do it, each offering a different separation with its pros and cons. Lets take a look on 4 ways how to factor out code from your monolithic Rails:
4 Ways to extract
Gem
Gems are great mechanism to extract features for your overloaded Rails app in case you have cohesive set of objects, which are or could be separated from the rest of the application (and framework).
What works really well is to start gathering the classes, minimize their interaction with objects within your Rails app and gather them under a common namespace - you can get those files into
lib/folder (temporarily!). Once you’re done with separation, create new gem and pull the code out of the Rails. This would force future developers to think in separated concerns, greater reducing the dependancies among system componets.Start small, make sure creating, releasing gems and updating your bundles is really cheap (=automated) and bite one thing at a time from your app.
Start with logger, background jobs, email notifications - simple things, which can be abstracted and closed in a gem. Imagine the case you wanna switch the background jobs from delayed job to sidekiq. Team working on Rails app wouldn’t even have to know (and adjust any code) when background jobs gem is updated.
Gems are perfect to separate your core domain model as well. At the end your domain should be framework agnostic, right?
Rails Engines
Rails engine can be understood as the plugin to your Rails application.
They are best suitable if you intend to slice piece of your application (or build new slice) from the database to UI. They contain its own models, views, controllers and also routes and dependancies.
There are two types of engine:
fullandmountable.If you are building new cluster of features, which should integrate with rest of your application I would recommend to directly start a
mountableengine. One of its benefits is that its better separated, which is enforced by its own namespace. It gets integrated to your Rails app as any other gem.The
fullengine is not separated by a namespace (by default) so its more suitable in case you wanna extract existing feature set out of a monolithic app. I believe the extraction of code is already very challenging task, so less extra gymnastics you have to do is better. You can basically start by moving code around with minimum changes (ofc you first need to decouple cohesive set of code to pull).Conclusions
Ok, i said 4 ways, but the post would be rather long. Let me sum up here and introduce the rest in follow up blog post, where we would discuss even further separation when application runs on its own server.
I didn’t really find magical way how to make the Rails app smaller, but one thing is clear - it would pay off if you do it at the right time.
Monitor your process and find a good timing for it. Separation would bring certain level of overhead (releasing gems, managing versions, integration, …), but at the same time more cohesive design where each system component limit interaction with others and therefore offer greater independence of your teams, which can then go faster.
-
alan dipert: Passing Methods like Blocks in Ruby
Ruby’s Functions
Ruby has four flavors of function, each with various nuances: methods, blocks, Procs, and lambdas.
A Simple Example
The object Array has a bunch of methods on it that take blocks. Normally, you write these blocks inline:
[1,2,3].map{|x| x+1} # → [2,3,4]But what if you…
-
Quote
"We’re in a world where hip creative directors are being positioned against ad monitoring technology that is able to create and serve the best-performing ad… regardless of how lacking it may be of creativity and a big idea."
-
Code smells: Control couple
Detecting smells is just a first step. We can help with that in Sniffer. Taking an action is although your turn, because at the end its your code and you wanna get it cleaner and nicer. This is the first post in serie about code smells. I would like to reason about how they look like and how to clean them.
Lets get started. First one is Control Couple.
How does it look like
Control couple happens if your method code, check for a parameter value to decide the execution path.
Lets take a look at very simple example.
class PersonGreeting def initialize(name) @name = name end def greet(shout = false) if shout puts "Hi, #{@name.upcase}!" else puts "Hi, #{@name}!" end end end PersonGreeting.new('Petr').greet(false) #= "Hi, Petr!" PersonGreeting.new('Petr').greet(true) #= "Hi, PETR!"Its obvious that client code already knows if he wanna shout or not. Passing the controlling parameter makes your code less flexible and more complex.
Complexity grows because you have code branching with if statement. In more complex examples and in cases when even more control couple variables are passed it might lead to if/else maze. Its basically violation of SRP (Single Responsibility Principle) because your code would do more then one thing.
Flexibility is lost, because any change in control couple parameter needs to be reflected on both sides of the call.
Not an ideal case at all. Lets get rid of it.
Cleaning up
Lets continue with our simple example and refactor code to:
class PersonGreeting def initialize(name) @name = name end def greet "Hi, #{@name}!" end def greet_shouting "Hi, #{@name.upcase}!" end end PersonGreeting.new('Petr').greet #= "Hi, Petr!" PersonGreeting.new('Petr').greet_shouting #= "Hi, PETR!"Well thats better. You can see PersonGreeting methods got simple and none of them does two different things. In this case it might be enough, but I would like to consider one further refactor:
class PersonGreeting def initialize(name) @name = name end def greet "Hi, #{@name}!" end end class PersonShoutGreeting < PersonGreeting def greet "Hi, #{@name.upcase}!" end end PersonGreeting.new('Petr').greet #= "Hi, Petr!" PersonShoutGreeting.new('Petr').greet #= "Hi, PETR!"This is a simple example of strategy pattern. We have created base class with default behavior and inherited the concrete shouting implementation. In this case we even leveraged SRP from method level to class level, which means, each class is really doing just a single thing.
In this stage we got a way better flexibility. We can introduce all bunch of new Greeting objects like PersonPoliteGreeting or PersonFriendlyGreeting. Each of them become just another strategy to our greeting mechanism. Their implementation would be very simple and client code can directly choose one of them to be used.
Conclusion
Keep your objects simple. Take care each method does just a single thing. Same applies to classes. Each class should have just single responsibility. Of course, definition of responsibility should be flexible to your project. Using the if/else statements might be the good lead. Its sign that your code is starting to do two different things. As responsibility of that object grows, it would be probably good idea to split it. Strategy pattern might do the best job for you, in case different if branches choose different ways to handle the similar thing.
2 weeks ago
blog comments powered by Disqus
3 weeks ago
blog comments powered by Disqus
1 month ago
blog comments powered by Disqus
1 month ago
blog comments powered by Disqus
6 months ago
blog comments powered by Disqus
