Practical Object-Oriented Design in Ruby: An Agile Primer (Addison-Wesley Professional Ruby)
All
Hacker News 7
This Year
Stack Overflow 2
This Month
Stack Overflow 2
I would wrap functionality in modules and classes, as there are some benefits to it:
a) you can easily write tests for code in classes (and for modules by including them in classes as mixins and testing the classes) b) you have control over the visibility of functions/methods and you can actually create an interface in case you have a consumer of the game that needs to access something more than just the game class c) it's easier to extend the functionality of parts of the game by creating new implementors of parts of the game's functionality
That said, there is no dogma on writing only in an Object Oriented way. In some cases (perhaps for scripts that will be used as command line scripts), just having some functions and code executing those functions might be enough (especially if the script is simple and short in general).
My advice regarding the structure of the little game you're building is to look for the interactions, the "verbs" that need to take place (ie the messages sent between objects) and then you'll come up with the classes that will send those messages (methods) and designing and structuring the game will get much easier I believe.
By the way, a good book that could help in the direction of designing software is the following:
http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330
Hope the above help.
http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-...
It takes the cognitive overhead off of the programming language completely and focus on design principles in a really modern learning style.
Models in Rails do not have to do database operation, they are just normal classes. Normally they are imbued with ActiveRecord magic when you subclass them from ActiveRecord::Base.
You can use a gem such as Virtus that will give you models with attributes. And for validations you can go with Vanguard. If you want something close to
ActiveRecord
but without the database and are running Rails 3+ you can also includeActiveModel
into your model to get attributes and validations as well as have them working in forms. See Yehuda Katz's post for details on that.In your case it will depend on the data you will consume. If all the datasources have the same basic format for example you could create your own base class to keep all the logic that you want to share across the individual classes (inheritance).
If you have a few different types of data coming in you could create modules to encapsulate behavior for the different types and include the models you need in the appropriate classes (composition).
Generally though you probably want to end up with one class per resource in the remote API that maps 1-to-1 with whatever domain logic you have. You can do this in many different ways, but following the method naming used by ActiveRecord might be a good idea, both since you learn ActiveRecord while building your class structure and it will help other Rails developers later if your API looks and works like ActiveRecords.
Think about it in terms of what you want to be able to do to an object (this is where TDD comes in). You want to be able to fetch a collection
Model.all
, a specific elementModel.find(identifier)
, push a changed element to the remote serviceupdated_model.save
and so on.What the actual logic on the inside of these methods will have to be will depend on the remote service. But you will probably want each model class to hold a url to it's resource endpoint and you will defiantly want to keep the logic in your models. So instead of:
you will do
or more probably
Basic principles: Collect all the shared logic in a class (ApiClient). Subclass that on a per resource basis (User). Keep all the logic in your models, no other part of your system should have to know if it's a DB backed app or if you are using an external REST API. Best of all is if you can keep the integration logic completely in the base class. That way you have only one place to update if the external datasource changes.
As for going the other way, Rails have several good methods to convert objects to JSON. From the to_json method to using a gem such as RABL to have actual views for your JSON objects.
You can get validations by using part of the ActiveRecord modules. As of Rails 4 this is a module called ActiveModel, but you can do it in Rails 3 and there are several tutorials for it online, not least of all a RailsCast.
Performance will not be a problem except what you can incur when calling a remote service, if the network is slow you will be to. Some of that could probably be helped with caching (see another answer by me for details) but that is also dependent on the data you are using.
Hope that put you on the right track. And if you want a more thorough grounding in how to design these kind of structures you should pick up a book on the subject, for example Practical Object-Oriented Design in Ruby: An Agile Primer by Sandi Metz.
Accessing the attribute through the getter has the advantage of providing encapsulation. The use of an instance variable to store the value is an implementation detail in some respects. Whether that's appropriate is, of course, situational. I don't recall reading anything explicit this style issue, however.
Found https://softwareengineering.stackexchange.com/questions/181567/should-the-methods-of-a-class-call-its-own-getters-and-setters, which discusses the issue from a language-independent point of view. Also found https://www.ruby-forum.com/topic/141107, which is ruby-specific, although it doesn't break any new ground, let alone imply a Ruby standard.
Update: Just came across the following statement on page 24 of http://www.amazon.com/Practical-Object-Oriented-Design-Ruby-Addison-Wesley/dp/0321721330/ref=sr_1_1?s=books&ie=UTF8&qid=1376760915&sr=1-1, a well-respected book on Ruby: "Hide the variables, even from the class that defines them, by wrapping them in methods." (emphasis added). It goes on to give examples of methods in the class using the accessor methods for access.
A module should contain code that is shared by different classes, or it can be added to a single class.
No, you can achieve the same thing with inheritance. If there is no code to share, then you probably don't need a module.
You can access them using the class from within a controller:
"Module or class?" is an age-old question in Ruby, and any other language that supports both.
I would encapsulate the functionality for each API in a class. For example, you can have a
SalesForceAPI
class. Then, if you need to share functionality between the classes for authenticating, creating a folder, auditing files, or downloading files, you can create anAPI
class.Each of the classes that needs access to the
API
class would inherit from it:You can achieve the same thing by creating an
API
module, and mixing it into the other classes. In this case, it's largely a matter of preference, because either solution is good.FWIW, I don't know if there would be much shared functionality for authenticating, creating a folder, auditing files, or downloading files, because each API can work quite differently. However, if they are REST API's then you may create some REST helper methods and put them in the
API
class.A great, easy to understand, and complete resource on the topic is Practical Object Oriented Design Ruby.
All this is only my personal opinion on this broad and open topic. Some people might disagree and funny enough they can.
As of general guidelines you should use Cucumber to test entire application stack, something that is called user experience. This application stack might be composed of many smaller independent objects but, same as user using your application wouldn't be interested in those details, your cucumber test shouldn't care for them and focus instead on outer layer of your application.
RSpec( in your setup!) should on the other hand put a main focus on those small objects, building blocks of your application.
There is a big problem with small application examples from the books: They are to small!
Boarder between outer layer of your application and its interiors is to blurred. Entire application is build with two objects! It is hard to distinguished what should test what. As your application grow in size its getting more obvious what is a user experience test(cucumber) and what is object - state test/message expectation test(RSpec).
Using your second example:
With this Cucumber story:
Rspec:
You will probably have some sort of User model:
You can have some sort of authentication object:
What if your Authentication database is on different server?
And yada yada yada... Forever your cucumber test will guard general purpose of your application user login. Even when you add or change behaviour, under the hood, as long as this test pass you can be confident that user can login.
Generally your question is too broad and you wont find a single answer, different people will have different ideas. What you should focus on is to test, as good as you can and with time you will definitely find right way for you. Not a great test suit is much better then none.
Because good design helps to write good test I would recommend Practical Object-Oriented Design in Ruby: An Agile Primer by Sandi Metz(which is one of a best book I've read)
In Practical Object-Oriented Design in Ruby, what Sandi Metz recommend you do to overcome calling super is to define a "hook" method in the super-class, which only job would be to get over-written by the child methods. In your case, you could do something like this: