CSC/ECE 517 Fall 2013/ch1 1w34 fs: Difference between revisions
No edit summary |
No edit summary |
||
Line 1: | Line 1: | ||
'''Aspect-Oriented Programming''' ('''AOP''') in '''Ruby on Rails''' is a programming paradigm which aims at preserving the modularity of object –oriented programs by separating behaviors that make overall implementation scattered, bulky and tangled. It so happens with huge applications that the object boundaries in the problem domain get obscured with the introduction of more and more aspects as an application gets bigger leading to spaghetti code scenario. AOP thus compliments the object-oriented principles such as '''DRY ''' by removing excess duplication throughout the program by handling cross-cutting concerns, making the resulting code as highly modular, easy to maintain and test. | [[File:Aspect1.jpg]] | ||
[[File:Aspect2.jpg]]'''Aspect-Oriented Programming''' ('''AOP''') in '''Ruby on Rails''' is a programming paradigm which aims at preserving the modularity of object –oriented programs by separating behaviors that make overall implementation scattered, bulky and tangled. It so happens with huge applications that the object boundaries in the problem domain get obscured with the introduction of more and more aspects as an application gets bigger leading to spaghetti code scenario. AOP thus compliments the object-oriented principles such as '''DRY ''' by removing excess duplication throughout the program by handling cross-cutting concerns, making the resulting code as highly modular, easy to maintain and test. | |||
Revision as of 02:04, 8 October 2013
Aspect-Oriented Programming (AOP) in Ruby on Rails is a programming paradigm which aims at preserving the modularity of object –oriented programs by separating behaviors that make overall implementation scattered, bulky and tangled. It so happens with huge applications that the object boundaries in the problem domain get obscured with the introduction of more and more aspects as an application gets bigger leading to spaghetti code scenario. AOP thus compliments the object-oriented principles such as DRY by removing excess duplication throughout the program by handling cross-cutting concerns, making the resulting code as highly modular, easy to maintain and test.
By isolating behavior, tight coupling between functionalities handling specific logic, in a program can be prevented. Also these independent aspects such as logging, transactions and security can be applied to other applications as well.
Overview
History
Terminology
Cross Cutting Concerns
Many applications share common functionality in their design and implementation. This shared and common logic spans across many layers and leads to repetition and bloating of the application and thereby termed as crosscutting concerns. The aim of AOP is to centralize these functionalities into modular and independent logical aspects which can be inserted into the application either during compilation or at run time, as per requirement, thereby complimenting the DRY principle. The benefits of adopting such an approach are many. Apart from keeping the application with distinct object boundaries, it modularizes aspects in separate locations which are easy to update and maintain in future as well as reuse in other web applications. Some such aspects known commonly which can be treated in AOP way are:
Authentication authorization caching communication logging validation
This reusing behavior as per outside defined aspects, crosscutting concerns can be effectively dealt with.
Advice
Point-cut
Aspect
AOP Interactions
AOP'istic flavored Rails Framework
Rails framework allows methods to be called before and after a method invocation by employing method aliasing and metaprogramming features of Ruby, but using a third party library such as Aquarium, to glue the aspects is more cleaner and robust to failures ( such as plugins overriding method_missing stepping over each other). Rails already provides for filters which can be called before, after or around to wrap the controllers such as shown here:
someController before_filter :admin_login_required
We also show how aspect oriented programming can be employed in Rails framework by separating aspects which cross-cut the application. In the following example we illustarte it for Loggingaspect. We start by building an application which stores items to be purchased in a cart. To help log user's activity while successfully adding or removing the items, logging needs to be performed for each action. As application gets bigger more aspects need to corporated such as authentication, security etc which makes it difficult to maintain and understand the code. Also it is needed for any update to any aspect be applied everywhere in the business logic where that updated aspect was injected.
class ItemsUseCase attr_reader :cart, :logger, :items def initialize(cart = cart.new, logger = Logger.new) @cart = cart @logger = logger @items = [] end
# Logging Aspect for adding items to cart def user_adds(item) items << item cart.add(item, success: self.method(:user_added), failure: self.method(:fails_to_add)) end def user_added(item) logger.info "Item successfully added: #{item.name})" end def fails_to_add(item) logger.error "Failed to add item}" end end
Introducing AOP concept for separating Logging aspect. By separating the logging aspect to ItemsUseCaseGlue, we see that our ItemsUseCase become much simpler and having comprehensible object boundaries. It handles all the above stated issues that comes with integrating aspect knowledge in the business logic.
class ItemsUseCase attr_reader :items def initialize @items = [] end def user_adds(item) items << item end def user_added(item); end def fails_to_add(item); end end
ItemsUseCaseGlue, where we employ Aquarium for employing AOP concepts, method invocation using- calls_to is used to specify our Joint points. When invoked in the program, advice is injected to take effect before, after or around the joint point.
require 'aquarium' class ItemsUseCaseGlue attr_reader :usecase, :cart, :logger include Aquarium::Aspects def initialize(usecase, cart, logger) @usecase = usecase @ cart = cart @logger = logger end def inject! Aspect.new(:after, object: usecase, calls_to: :user_adds) do |jp, obj, item| cart.push(item, success: usecase.method(:user_added), failure: usecase.method(:fails_to_add)) end Aspect.new(:after, object: usecase, calls_to: :user_added) do |jp, obj, item| logger.info("Successfully added: #{item.name})") end Aspect.new(:after, object: usecase, calls_to: :fails_to_add) do |jp, obj, item| logger.error "Failed to add item" end end end
Finally, the application retains its pure domain object properties without including any aspect layer specifications.
class Application def initialize @items = ItemsUseCase.new @cart = Cart.new @logger = Logger.new @items_glue = ItemsUseCaseGlue.new(items,@cart, @logger) @items_glue.inject! # logic end end
==Summary==
External Links
- http://java9s.com/spring-framework/spring-aop-tutorial-aspect-oriented-programming
- http://guides.rubyonrails.org/action_controller_overview.html
- http://www.codeproject.com/Articles/11385/Aspect-Oriented-Programming-in-NET
- https://en.wikipedia.org/wiki/Cross-cutting_concern
- http://msdn.microsoft.com/en-us/library/ee658105.aspx
- http://aquarium.rubyforge.org/examples.html