I've been looking for good practices for Rusy Sinatra and I found this question here on stackoverflow:
Using Sinatra for larger projects via multiple files
However, I am wondering what to do in case the business logic behind some route is big. Wouldn't be better to wrap it in a class (helper/utility) and just delegate to it from the route ?
I my opinion this will keep the controller clean and easy to follow.
What would be the best folder to place such a utility class ?
The pattern we use where I work is:
Sinatra Web Handler -> 'Processor' class (encapsulates business logic in a reusable route, sometimes behind facades). The processor does any ORM or cache operations which might be necessary, and knows when to delegate to further downstream processors (or, even, other internal / external services).
This decouples the sinatra routes from the application logic, and means that we can plug those processor classes. We try to keep the processor classes related to one business process, for e.g. User creation, and write them in such a way that we can plug them onto other endpoints as and when we desire. We're in effect using Sinatra as an HTTP request router into our main application.
It seems to work pretty well.
Related
I'm still in a learning phase with PHP and Laravel 5 and since I upgraded to L5, I struggle with where my code belongs to. There are so many files and folders which seem to have the same purpose or at least are very similar. There are Commands, Controllers, Events, Services, Requests, etc. I give an example with my workflow and where I would place the code and I hope you guys can comment on that and correct/help me.
Situation
I want to register a new user in my application and send a welcome e-mail when he registered successfully.
Workflow
Controller (UserController): Returns requested view (register).
Request (RegisterRequest): The "RegisterRequest" validates the entered data.
Controller (UserController): Passes the validated data to the "UserRegistrar" (service) in 'App/Services'.
Service (UserRegistrar): Creates a new user and saves it to the database.
Controller (UserController): Fires the "UserWasRegistered" Event.
Event (UserWasRegistered): This Event call the "SendWelcomeEmail" Command.
Command (SendWelcomeEmail): This Command will send/queue the welcome e-mail.
Controller (UserController): Redirects the user to a view with the information that he has been registerd successfully and a message has been send to him.
Logic
Okay, let's discuss some logic:
Controller:
Doesn't hold much code.
Mainly there to return views (with requested data).
Handles workflow and "connects" modules (Services, Requests, Events).
Request: Validates the data for a specified request
Service: A service "does" something. For example it's doing requests to the database.
Event: An Event is a central place to call one or more tasks if it is fired (SendConfirmationMail, SendWelcomeMail).
Command: Mainly there to handle the logic for ONE certain task. For example sending a confirmation mail. Another command will hold the logic for sending the welcome mail. Both commands are called in the Event described before.
Repositories: What is that?!
So this is what I understand. Please help me and feed me with information.
Thanks,
LuMa
Your question is a little vague and will likely attract downvotes as being "too broad". That said, here's my take on this...
The biggest issue I see is that your application structure is very different from the recommended L5 structure - or even the standard MVC structure - that it's no wonder you're getting confused.
Let's talk about your "Logic" section:
controller - you're on the right track here. The controller is the glue between your models and your views. It can do some processing, but most should be offloaded to classes that handle specific tasks.
request - what is this? L5 includes a Request class that includes methods for examining the HTTP request received from the client. Are you talking about subclassing that? Why? If your idea of a "request" class is primarily concerned with examining input, you can either do that in your model (ie. validating stuff before sticking it in the database) or in your controller (see the L5 docs on controller validation)
service - again, what is this? You talk about "doing requests to the database", but L5 provides a class for that (DB). At a higher level, database access should primarily be done through models, which abstract away most of the low level database access. As for other services, what I usually do is create libraries to perform specific processing. For example, my application has a particular third party project management application that it accesses via an API. I have a library for that, with methods such as getProject or createProject.
event - An event is a way of ensuring that some code is called when the event happens, without a whole lot of messing about. It sounds like you have the right idea about events.
command - again, it sounds like you have the basic idea about commands.
repositories - these are way of abstracting the connection between a resource (primarily the database, but it can apply to other resources too) and the code that uses the resource. This gives a way to switch the underlying resource more easily if you (for example) decide to change database servers in the future. They are optional.
You also haven't mentioned anything about models. L5 provides an excellent way to deal with your data in understandable chunks via Eloquent models - this will make your life much easier.
My suggestion is this: start small. Build a simple MVC application with L5 - A model (to save some data), a view (to display the data), and a controller (to put the model & view together by handling the client request). Once you have that, start extending it.
There are tutorials out there that will give you this basic structure for Laravel - most are for Laravel 4, but see if you can follow the basic ideas and build something similar for Laravel 5.
In MVC and most other service frameworks I tried, caching is done via attribute/filter, either on the controller/action or request, and can be controlled through caching profile in config file. It seems offer more flexibility and also leave the core service code cleaner.
But ServiceStack has it inside the service. Are there any reason why it's done this way?
Can I add a CacheFilterAttribute, but delegate to service instead?
ToOptimizedResultUsingCache(base.Cache,cacheKey,()=> {
// Delegate to Request/Service being decorated?
});
I searched around but couldn't find an answer. Granted, it probably won't make much difference because the ServiceStack caching via delegate method is quite clean. And you seldom change caching strategy on the fly in real world. So this is mostly out of curiosity. Thanks.
Because the caching pattern involves, checking first to see if it is cached, if not to then execute the service, populate the cache, then return the result.
A Request Filter doesn't allow you to execute the service and a Response Filter means that the Service will always execute (i.e. mitigating the usefulness of the Cache), so the alternative would require a Request + Response filter combination where the logic would be split into 2 disjointed parts. Having it inside the Service, lets you see and reason about how it works and what exactly is going on, it also allows full access to calculate the uniqueHashKey used and exactly what and when (or even if) to Cache, which is harder to control with a generic black-box caching solution.
Although we are open to 'baking-in' built-in generic caching solutions (either via an attribute or ServiceRunner / base class). Add a feature request if you'd like to see this, specifying the preferred functionality/use-case (e.g. cache based on Time / Validity / Cache against user-defined Aggregate root / etc).
I just completed writing a detailed rspec capybara integration and unit tests for Rails app, which includes mocking Omniauth (twitter) login, filling in forms, data validations, etc. However, I am wondering whether there is a need to write a separate controller or functional test.
Would appreciate your input and any links to further readings etc.
I'll play devil's advocate here, since I know I'm probably in the minority with this opinion: I actually prefer to do exceedingly thorough controller testing. A few reasons:
1) I find it easier to systematically test every path and outcome at the controller level than at the integration test level. My integration tests are primarily just happy-paths, and some of the more common error paths.
2) A lot of potential security issues occur at the controller level. Thorough testing helps me ensure that nothing malicious can get through to my model logic.
3) This is subjective, but it really forces me to think about some of the long-tail paths that my application might go through. What if someone tries to for an invalid password reset token into the URL? Controller testing ensures that I consider all options.
4) Unlike integration tests, they're fairly straight-forward to test. Each action is just a ruby method!
Personally, I think if your request (integration) spec is exercising all code paths you're covered. Ryan Bates has a great Railscast about how he tests here: http://railscasts.com/episodes/275-how-i-test?autoplay=true and about 5:05 in he says a similar thing. Like you I like to write integration tests rather than controller specs. Most of the time controllers simply front CRUD type operations anyway (especially if you're careful about keeping domain logic out of the controller), so all you're testing is the scaffolding.
I am writing a Ruby on Rails app. which will use a 3rd party to do a webservice call or a rest call or some sort of call. I am not sold on which 3rd party I am going to use so I want to isolate this in some sort of facade.
If I was doing this in .NET, I would isolate this functionality in a service that I inject into the controller. This means I can easily mock out the service in order to make it testable but in ruby, it is much easier to mock things so I don't think I need this level of indirection and de-coupling that I would need in a static application.
This feels very un-ruby-like and I would like to hear how more experienced ruby developers approach this problem of isolating the code to make it mockable and testable and also give me the option to swap which 3rd party provider I am using.
If it is a RESTful webservice, I would do this in a model that inherits from ActiveResource::Base. It should be relatively easy to mock this out as well for testing purposes.
The ruby-like version of "I would isolate this functionality in a service that I inject into the controller" would be something like "I would write this as a ruby module that I include in my class"
So I'm trying to figure out a way of stubbing a controller method in rspec for a Sinatra app. The main reason for this is to test the logical flow of the application and to make sure it calls the necessary functions when certain conditions are met. So, in essence, I want to be able to do something like
controller.should_receive(:fancy_method).and_return("This is a string")
What I'm having difficulty doing is accessing the controller instance within the sinatra app. I am able to override the current functions using a class_eval on the sinatra controller class, but I'd love to assert that these functions actually run.
Anyone have any advice?
Thanks.
Dan, I believe what you really want is to just test the controller actions. From a tester's perspective you shouldn't really care about what it actually called but rather for the output, given a specific input and maybe some other special conditions (that is mocking or stubbing other classes) (1).
You can check the official documentation for Sinatra + Rack::Test or this blog post from devver.net.
(1) : If your controller pages are calling some other classes (models, services, etc) you could mock these instead and put expectations on them. For example :
SomeClass.should_receive(:msg).with(:arg).and_return(:special_value)
Some more info for mocking (with RSpec in this exmaple) can be found on the RSpec documentation pages.