background
I'm writing an API that processes data from an external application. My application processes JSON responses from the external application and offers relevant information to consumers of my service. (These consumers are internal to my organisation)
The external application has an API that allows me to check for updates. Updates are triggered by events. The API offers 12 different types of events. The event types are offered in a string format. (ex. 'MoveEvent', 'DeleteEvent', 'CreateEvent')
I need to write a specific processing algorithm for each event.
Problem
I'm looking for a clean, DRY and SOLID way to implement the event processing system. The focus for this application is on code quality and a solid architecture.
My solution and thoughts
There are a number of ways to tackle this issue, but my best guess so far has been:
Create a hash that holds the string name of the event types and map them to a processing class.
Use the Strategy pattern to define a common interface for all the processing classes to adhere to, so that any mediating class only needs to know the message to which the processing classes can respond.
Use some sort of factory (method) to instantiate a concrete implementation.
I'm explicitly looking to ignore a long if-elsif-else solution, unless someone can convince me to do otherwise.
Suggestions and criticism is always welcome, thanks!
In this type of situation, I like to use this pattern:
class Processor
class << self
def for(name, data)
processors[name].new(data)
end
def processors
{
'MoveEvent' => MoveEventProcessor,
'DeleteEvent' => DeleteEventProcessor,
'CreateEvent' => CreateEventProcessor
}
end
end
attr_reader :data
def initialize(data)
#data = data
end
class MoveEventProcessor < Processor
#... code to handle this event
end
class DeleteEventProcessor < Processor
#... code to handle this event
end
class CreateEventProcessor < Processor
#... code to handle this event
end
end
p Processor.for 'MoveEvent', {some: :data}
So my suggestion would be to not over engineer this chances are that you will have to iteratively refactor or reimplement your solution as you become aware of things. I think the first Idea you came up with is probably the most straight forward way to go about it. Even if you want to house that hash inside of a class that then handles and required processing of the selected event class that would still seem reasonable (so basically number 2). ReggieB's answers is about what I would expect.
Related
I have a class A with a method M for which I want to write a test T. The problem is that method M creates a new object O. I want to mock a method F of that new object O.
class A
def M(p1, p2)
#o = O.new(p1, p2)
end
end
class O
def F(q)
...
end
end
I can very easily do so with the allow_any_instance_of feature of RSpec, but I really don't see a way of doing so with just allow or expect. I understand that I can mock a method of an existing instance and of a class but from my tests I couldn't make it work against methods of objects that get created in a method I'm testing.
T :process do
it "works" do
# This works
allow_any_instance_of(O).to receive(:F).and_return(123)
...
end
it "does not works" do
# This fails
allow(O).to receive(:F).and_return(123)
...
end
end
How do I know that it fails?
I changed my F method with a puts() and I can see that output on the screen when I use the allow(O). It does not appear at all when I use the allow_any_instance_of(). So I know that it's working as expected only in the latter.
def F(q)
puts("If I see this, then F() was not mocked properly.")
...
end
I would think that allow(O)... should connect to the class so whenever a new instance is created the mocked functions follow, but apparently not.
Do you have RSpec tests handling such mocking cases in a different way that would not involve the use of the allow_any_instance_of() function?
The reason I ask is because it is marked as obsolete (#allow-old-syntax) since RSpec 3.3 so it sounds like we should not be using this feature anymore, especially once RSpec 4.x comes out, it probably will be gone.
The reason this
allow(O).to receive(:F).and_return(123)
Doesn't work is that :F is not a method of O, so the O never receives this message (method invocation).
The best solution for you would be to refactor your code to use dependency injection. (Please note that your example is abstract to the extreme, if you provided a real life example - closer to the ground - some better refactoring might be possible)
class A
attr_accessor :o_implementation
def initialize(o_implementation)
#o_implementation = o_implementation
end
def M(p1, p2)
#o = o_implementation.new(p1, p2)
end
end
RSpec.describe A do
subject { described_class.new(klass) }
let(:klass) { O }
let(:a_double) { instance_double(klass) }
it do
allow(klass).to receive(:new).and_return(a_mock)
allow(a_double).to receive(:F).and_return(123)
end
end
With the Dependency injection you move outside the decision which class to instantiate. This decouples your code (A stops being coupled to O, now it depends only on the O interface that it's using), and makes it easier* to test.
(*) One could argue that allow_any_instance is easier (less involved, less typing), but it has some issues, and should be avoided if possible.
(as a small aside: I can understand the probable need for very thorough anonymization of your code, but you could still follow ruby style guide: methods start with lower-case, only classes start with upper-case)
So first off: allow(O) works, but will only capture class methods. If you need to capture instance methods, you need to call allow for a specific instance.
Since your example is pretty sparse, I see no reason why we could not split up the creation of the object from the test? If that is possible, a very simple approach would be to write something like:
describe :process do
before do
#o = A.o_maker(p1,p2)
allow(#o).to receive(:some_function) { 123 }
end
it "works" do
# do something with `#o` that should call the function
end
end
I personally prefer this approach over creating the mock class, as suggested before.
This is probably well known, but for clarity: the problem with a mock class imho is that you are no longer testing class A but the mock. This could in some cases be useful, but from the original question it is unclear if it applies in this case and if this is not needlessly complicated. And secondly: if your code is this complicated (e.g. some method that creates a new object and then calls F), I would rather 1) refactor my code to make it test-able, and/or 2) test side effects (e.g. F adds an audit-log-line, sets a state, ...). I do not need to "test" my implementation (is the correct method called), but is it performed (and of course, as always, there are exceptions e.g. when calling external services or something --but again all that is impossible to deduce from the original question).
I just inherited an RoR codebase, and in many of the controllers I see the following style of code:
ABCService.new.do_foo
I have been working on RoR codebases for quite a long time, but I fail to understand why the .new. style is used. The service classes in question do not hold any state (even with class-level variables) and the same can be achieved with self (ie class-level) methods - so, any explanation of why this style is better? To me, it looks like some java developers coded this app and "ported over" some coding paradigms from that language.
Making service objects stateful as a convention has its benefits:
Minimal refactoring when one of them requires state
Easy to mock in tests without messing around with constants
Save brain juice on this decision when implementing a new service object
That being said, whether this is beneficial for your codebase is something you / your team need to assess as part of defining your own architectural / code style conventions.
It can be quite irritating to always have to call Klass.new.do_something. You can wrap it in a class method, eg:
class Service
class << self
def do_something
new.do_something
end
end
def do_something
end
end
"Right tool for the job"
Having only class method, will explicitly tell other developers/readers of your code, that this service doesn't have state.
Even better, use module instead of class, then your intentions would be clear for others and for later you.
When you need state, use instance method.
For example you can have service which accepts two arguments, first one is argument which should be used for all calls of this service, but second can be change for every call.
class AddTax
def initialize(tax_rate)
#tax_rate = tax_rate
end
def to(amount)
amount * (1.0 + #tax_rate)
end
end
# Usage
prices = [20, 100, 50, 49, 50]
add_tax = AddTax.new(0.24);
with_taxes = prices.map { |price| add_tax.to(price) }
I have a model Project that appears in multiple controllers in an application I'm building as it appears on multiple pages. The where clause for this isn't complicated, per se, but I feel like it is too large to be repeated on every method requiring projects with these constraints.
My question is, where, if possible, does this common call for Projects go? In .NET, I'd have a ProjectService class with a method that would return all projects, and another that returned all projects that satisfied my conditions. I'm new to Rails so I'm struggling to see where this fits in?
You can either use a class method or Scopes.
class Project < ActiveRecord::Base
# example for a scope
scope :awkward_projects,where(awkward: true)
# example for a class method.
def self.awkward_projects
where(awkward: true)
end
end
Its very safe to do what was once given in a SO answer. Read below and choose carefully.
Quoting an answer
"Generally, I use scope entries for simple one-liners to filter down my result set. However, if I'm doing anything complicated in a "scope" which may require detailed logic, lambdas, multiple lines, etc., I prefer to use a class method. And as you caught, if I need to return counts or anything like that, I use a class method."
If you have two methods in a model or controller and you want to pass a variable between methods e.g.
def foo
#param = 2
#test = 1
callee
#do something with #test
end
def callee
#test += #param
end
Is it better to use instance variables to do this or regular variables like so
def foo
param = 2
test = 1
test = callee(param, test)
#do something with test
end
def callee(param, test)
test += param
test
end
Thanks in advance!
There isn't a definite answer to this question, it depends a lot on the context - the thing you need to ask is "which approach best demonstrates the intent of the code". You should definitely have tests for the model/controller class you are talking about.
As a very rough guideline:
The first approach is commonly seen when the method is part of the class's public API and it alters the internal state of instances of the class (although it may be the sign of a code smell if you have public methods chained as in your example.) This is probably going to be seen more often in a model object.
The second approach is usually seen when the method you are calling is a private convenience method that factors out some code duplication, or a method which does very specialised operations on the parameters and returns some result (in which case it should probably be factored out into a utility class.) This may be seen in model or controller objects.
If you are aiming for maintainable OO code, then the principles of SOLID design are very good guidelines - have a look at Uncle Bob's article about them here:
http://blog.objectmentor.com/articles/2009/02/12/getting-a-solid-start
It depends on your needs. Also, prototype of the function that you are passing variables to is also important. If you want the method not to change any of the parameters without your permission, you should use your second implementation. But, if you trust the function, you can use first method. This is a big topic called as "call by reference" and "call by value". You can examine following link;
http://www.exforsys.com/tutorials/c-language/call-by-value-and-call-by-reference.html
If the end_user cannot access the source code of the app, why we still need to make some methods private?
I'm reading the Pragmatic Agile Web Development with Rails and I couldn't understand why we need to make the following method private (even after reading the explanation):
private
def current_cart Cart.find(session[:cart_id])
rescue ActiveRecord::RecordNotFound
cart = Cart.create
session[:cart_id] = cart.id
cart
end
end
It says that it will never allow Rails to make it available as an action, but as a coder, why would I ever do that myself?
As you say there may be no external reason to make it private. However, it also prevents you — or somebody else using your code — from accidentally making use of the method where you're not supposed to.
See it as a sanity check on your own future behaviour if you will.
It aims to encourage good practices and good code.
The idea is that you have two separate parts to your code:
"Above the line" (Public). This is the interface to the rest of the world. This is the API, where calls are made when using instances of the object. Once created, you know that THIS is the area where changes can affect current usages of the code.
"Below the line (Private). This is where detailed logic resides. This code can be changed and refactored freely without any affect to the public interface.
It may help guide your test writing
Private methods may or may not be (unit) tested.
Public methods are more encouraging of both unit and integrated tests as the fact that is is public means that it is serving as the public face for that code and as it is public it might be called from any other point in the future, so having good tests to make sure it continues to work as advertised is essential.
It may help with security as you have greater control who calls private methods (i.e. only public methods in the same class calling them).
It may help reduce name collisions as you have less names in the public space.
End user might not be able to access your code but someone else in your team can definitely access it and they might change it.
The other benefit of encapsulation is that it allows one class ("server") to make a contract with another class ("client") to provide some service with only a very few things being required to be known about the "server" class such as method signature and return type. The benefit is only realized if the contract of what is required and what is returned remains the same. So, in your example, there is no benefit since the contract was broken by Class A.
Instead of class A changing int type to float, class A should create another new variable of type float for other classes to use so that class B is not "broken" or that contract is not broken between them. Class C could refer to new float variable and Class B could still refer to old int variable and everyone is happy. Better yet, methods would used to retrieve values such as: "getUsersAddress" and "getUSersPhoneNumber" depending on what was wanted.
The real benefit of good encapsulation is that Class A can be completely re-written from top to bottom and as long as the contract is honored as to what Class A is expected to do(have methods "getUsersAddress" and "getUSersPhoneNumber"), then everything in Class B and C works the same. Think carefully about what is exposed and how it is exposed. Things that will change often and break other classes need to be considered carefully before exposing. Good encapsulation means hiding things that are expected to change often so to avoid breaking other classes.
It says that it will never allow Rails to make it available as an action,
Hmm, is this in a Rails Conroller class? And is the book you are working through written for Rails 2.x?
In Rails 2.x, by default any public method in a Controller can be triggered by someone accessing the url /name_of_controller/name_of_method .
But there are some methods in your controller that you don't want anyone on the web to trigger, they weren't intended as 'action methods'. So in Rails 2.x, you mark those as protected or private, something not public. "action method" means a method you intend to be directly triggered via a URL.
In Rails 3.x, routing has generally changed such that only certain methods you explicitly route to are available to be triggered via a URL. However, it might still make sense to mark non-action-methods in a Controller as protected or private so:
It's more clear from skimming the source which methods are action methods and which aren't
As a precaution in case someone changes the routing in such a way that would allow a URL to trigger those methods not intended as action methods
Or for general reasons of code organization that other answers mention, that are not specific to Rails controller classes.
There are several reasons as mentioned above. The interesting thing about this encapsulation in ruby is that it can be violated.
See the "send" method and its brother "public_send".
And for a very common metaprogramming technique that uses this method see:
dynamic finders