The Proxy pattern revisited.
Tags: ruby, designpatterns, proxy, metaprogramming
Published: 2018-02-25 23:49:43

---
title: The Proxy pattern revisited.
published: true
description: Creating proxies by using prepending and some meta-programming. 
tags: ruby, design_patterns, proxy, meta-programming
---

##Intro
The Proxy is one of the most popular design patterns in most programming languages. A Proxy is simply an object that sits between some client code and a service object. The client code deals directly with the Proxy, instead of the service object. 
<sup>[1](#serviceobject)</sup> 
This means that the Proxy can be used to mask the service object's physical location (a _Remote_ proxy), manage access to the service object (a _Security_ proxy), or just lazily initialize the service object (a _Virtual_ proxy).

## The old way
Whatever the use-case, the idiomatic Ruby way to implement a proxy has been by utilising the `method_missing` method, as described in Russ Olsen's seminal book [Design Patterns in Ruby](http://designpatternsinruby.com/).

```ruby
# the service object
class Account
  def initialize(balance)
    @balance = balance
  end

  def deposit(amount)
    @balance += amount
  end

  def withdraw(amount)
    @balance -= amount
  end

  def self.interest_rate_for(a_balance)
    a_balance > 10_000 ? '3.2%' : '5.5%'
  end

end

# the proxy object
class AccountProxy
  require 'etc'
  def initialize(real_account)
    @real_account = real_account
  end

  def method_missing(name, *args)
    raise "Unauthorised access!" unless Etc.getlogin == 'fred'
    @real_account.send(name, *args)
  end
end

## client code
acc = Account.new(100)
proxy = AccountProxy.new(acc)
proxy.deposit(10)
proxy.withdraw(50)

```

In this simple proxy example, we intercept all method calls to `AccountProxy`, do a basic security check and then delegate the method to the real `Account` object to do the actual work.

This is a concise and effective way to create a proxy in Ruby, but it has some weaknesses: 

1. The client code needs to call a separate Object, e.g. AccountProxy instead of Account. It's pretty obvious we're not dealing with the 'real' service object, which is not only a nuisance if you have to re-write existing client code, but may also lead malicious actors to try to by pass the proxy.
2. `method_missing` is a catch-all trap. It will catch every method call coming our way and we need to think long and hard about which methods we want to delegate to the 'real' object and which ones to handle in our proxy (`#to_s`, for instance)
3. Using `method_missing` has a performance hit. When calling a method on an object, the Ruby interpreter will first look all the way up the object hierarchy trying to find the method and -when it can't- will go back down the hierarchy tree and start looking for a `method_missing` implementation. This will happen for every single method call. 
4. Our proxy doesn't work with class methods. To do that we'd need a separate proxy object for `Account`'s singleton class. 


## The new way
A few years after Russ's book came out, Ruby 2.0.0 was released and introduced [Module#prepend](http://ruby-doc.org/core-2.2.0/Module.html#method-i-prepend_features). The way `Module#prepend` works is by inserting the prepended Module between the calling code (a.k.a the 'receiver' object) and the module or class that does the prepending.

Can you see the connection already? The prepended Module _sits between the receiver and a service object_. Sounds familiar? Oh yes, this is exactly what a Proxy is meant to be doing! 

Knowing this we can use the `#prepended` hook method to dynamically implement all methods of the prepending module in our proxy, making sure to add our extra security check, before calling the original method implementation.

```ruby

module Proxy
  require 'etc'

  # Dynamically re-creates receiver's class methods, intercepts calls 
  # to them and checks user before invoking parent code
  #
  # @param receiver the class or module which has prepended this module
  def self.prepended(receiver)
    obj_mthds = receiver.instance_methods - receiver.superclass.instance_methods
    obj_mthds.each do |m|
      args = receiver.instance_method(m).parameters # => [[:req, :x], [:req, :y]]
      args.map! {|x| x[1].to_s}
      Proxy.class_eval do
        define_method(m) do |*args|
          puts "*** intercepting method: #{m}, args: #{args}"
          raise "Unauthorised access!" unless Etc.getlogin == 'fred'
          super(*args)
        end
      end
    end
  end

end #module


class Account
  def initialize(balance)
    @balance = balance
  end

  def deposit(amount)
    @balance += amount
  end

  def withdraw(amount)
    @balance -= amount
  end

  def self.interest_rate_for(a_balance)
    a_balance > 10_000 ? '3.2%' : '5.5%'
  end

  prepend Proxy

end
```

All we're doing is taking advantage of the way `#prepend` affects the Ruby Object Model in order to find out which methods the intercepted object is defining and then implementing them in our proxy while adding our own code. To call the original implementation, we once again leverage the fact that the intercepted object is the parent of our proxy module, so all we need to do is call `#super` (no more ugly `#send` calls) 
    
![prepending_proxy_to_class](https://cacoo.com/diagrams/0iRB3WrIhseOvudw-33260.png)

Let's write some client code to exercise our account:

```ruby
acc = Account.new(100)

puts acc.deposit(10)
puts acc.withdraw(50)
puts Account.interest_rate_for(2000)
```

which outputs:

```shell
*** intercepting method: deposit, args: [10]
110
*** intercepting method: withdraw, args: [50]
60
5.5%

```



That's pretty cool, but the beauty of it doesn't end here. We can use the very same mechanism to intercept class method calls. All we need to do is prepend the Proxy to the Account's singleton class:

```ruby


class Account
  def initialize(balance)
    @balance = balance
  end

  def deposit(amount)
    @balance += amount
  end

  def withdraw(amount)
    @balance -= amount
  end

  def self.interest_rate_for(a_balance)
    a_balance > 10_000 ? '3.2%' : '5.5%'
  end

  class << self
    prepend Proxy
  end

  prepend Proxy

end
``` 

Once again, the Object Model is manipulated to our favour:

![prepending_proxy_to_singleton_class](https://cacoo.com/diagrams/Q1qefWY6I0sa0gOw-33260.png) 

And now by running our client code again, we see that both instance and class methods of the Account class are caught by the proxy:

```ruby
acc = Account.new(100)

puts acc.deposit(10)
puts acc.withdraw(50)
puts Account.interest_rate_for(2000)
```

which outputs:

```shell
*** intercepting method: deposit, args: [10]
110
*** intercepting method: withdraw, args: [50]
60
*** intercepting method: interest_rate_for, args: [2000]
5.5%
```

This way of proxy-ing has a number of advantages:

1. It's transparent. Client code doesn't need to change, it doesn't even need to know that a proxy is being used, we just need to prepend the proxy module to the service object class.
2. It's performant. Some basic benchmarking has indicated a 3-4x performance gain against a method_missing proxy. 
3. It works for both instance and class methods.

So there you have it: Another way of building proxies. Ruby keeps evolving and so do we. Happy 25th birthday!


<a name="serviceobject">1</a>: a Ruby object that encapsulates some business logic