Ruby를 배우는 Java 개발자가 알아야 할 10가지 part 1

Java 개발자가 알아야 할 10가지

RUBY-DOC.ORG의 “10 Things Every Java Programmer Should Know About Ruby”를 번역한 문서입니다.

Ruby는 OOP이기 때문에 Java 개발자는 매우 익숙하게 다가갈 수 있다. 하지만 Java 스타일로 Ruby 프로그래밍을 하려고 하면 Ruby가 줄 수 있는 많은 가능성을 놓치기 쉽다.

생각과 행동은 사용하는 언어에 의해 영향을 받게 된다. 이 글은 “Ruby가 Java 보다 우수하다”라는 주장의 글이 아니라, Java 개발자가 Java 스타일로 Ruby 프로그래밍하는 것을 피해서 Ruby 방식으로 프래그래밍하는 방법을 발견할 수 있게 해주기 위한 글이다.

프로그래밍에 대해서 생각하는 방식에 영향을 주지 않는 언어는 배울 가치가 없다 ? Alan Perlis

Item #10 Ruby의 규약(Convention)을 익혀라

  • ClassNames (클래스명)
  • method_names and variable_names (메소드명이나 변수명)
  • methods_asking_a_question? (질문형 메소드는 물음표 사용)
  • slightly_dangerous_methods! (중요한 메소드는 느낌표 사용)
  • @instance_variables (클래스 멤버 변수)
  • $global_variables (static 변수)
  • SOME_CONSTANTS or OtherConstants (상수)

Item #9 모든 것은 객체(Object)다

  • 클래스는 객체다!
  • Array는 배열 클래스 객체의 이름이다.
    새로운 객체를 생성하기 위해서는 특별한 문법을 사용할 필요 없이, 클래스 객체에 new 를 보내면 된다.

    a = Array.new
  • 이 방식은 팩토리 패턴을 필요없게 한다.
  • 클래스는 자신의 인스턴스를 만들 수 있기 때문에, 자체로 완전한 팩토리 객체다.

    def create_from_factory(factory)
      factory.new
    end
    obj = create_from_factory(Array)
    
  • Primitives도 없다!
  • 0.zero?    # => true
    1.zero?    # => false
    1.abs      # => 1
    -1.abs     # => 1
    1.methods  # => list of methods for object 1
    2.+(3)     # => 5  (same as 2+3)
    10.class   # => Fixnum
    (10**100).class
               # => Bignum
  • nil 도 객체다! (Java의 null)
  • a = nil
    a.nil?     # => true
    a.methods  # => list of methods
    a.abs      # => NoMethodError

    Java에서 null은 객체가 아니다. method 사용 불가. 참고

  • 객체가 아닌 것들
  • 변수명은 객체가 아니다
    블럭은 객체가 아니다.

Item #8 (거의) 모든 것은 메시지다

  • 이름을 객체에 묶는다. Binding names to objects (assignment)
  • 구조나 연산자를 조절한다. Primitive controls structures (e.g. if/else, while) and operators (e.g. defined?)
  • 객체에 메시지를 보낸다. Sending messages to objects
  • string.index("x")
        Send :index (with argument "x")
    string.length
        Send :length (with no argument)
    run_status_reports
        Send :run_status_reports (to self)
    1 + 2
        Send :+ (with argument 2) to the object 1
    array[i]
        Send :[] (with argument i) to the array

    Ruby 프로그래머는 obj.mothod를 객체에 메시지를 보내는 것으로 생각하는 경향이 있다.
    Java 프로그래머는 obj.method를 객체에서 메소드를 찾아서 그것을 호출하는 것으로 생각하는 경향이 있다.

    이 미묘한 차이는 매우 중요하다. 다음 클래스를 보면, 보내지는 모든 메시지를 저장했다가 그 메시지를 다른 객체에 보내는 클래스를 정의하고 있다.

    class VCR
      def initialize
        @messages = []
      end
      def method_missing(method, *args, &block)
        @messages << [method, args, block]
      end
      def play_back_to(obj)
        @messages.each do |method, args, block|
          obj.send(method, *args, &block)
        end
      end
    end
    
    vcr = VCR.new
    vcr.sub!(/Java/) { "Ruby" }
    vcr.upcase!
    vcr[11,5] = "Universe"
    vcr << "!"
    string = "Hello Java World"
    
    puts string
    # => Hello Java World
    
    vcr.play_back_to(string)
    puts string
    # => HELLO RUBY Universe!
  • 메시지를 사용해서 얻을 수 있는 것들…
  • - Remote Proxies – 원격 객체에 메시지를 자동적으로 보내준다.
    - Auto Loaders – 첫번째 메시지가 올때까지 기다린 후, 메시지를 로드한 후 일반적인 프록시처럼 행동한다.
    - Decorators – 원하는 메시지는 가로채고 나머지는 통과시킨다.
    - Mock Objects – 흉내(mock)낼 메소드를 작성한 후 나머지는 필요에 따라 위임하거나 무시한다.
    - Builders – 빌더에 호출된 메소드에 따라 XML/HTML/등등을 생성한다.

Item #7 Ruby는 매우 동적이다

  • Java는 C++ 보다 동적인 언어다. 하지만 Ruby는 Java보다 몇 단계 더 동적이다.
  • - method_missing
    위의 VCR 클래스 참고

    - 쉬운 리플랙션(Reflection)
    [Java Code]

    public static Object create(Class c, String value)
      throws Exception
    {
      Constructor ctor = c.getConstructor(
        new Class[] { String.class } );
      return ctor.newInstance(
        new Object[] { "Hello" } );
    }
    
    public static void main (String args[])
      throws Exception
    {
      Greeting g =
        (Greeting) create(Greeting.class, "Hello");
      g.show();
    }

    [Ruby Code]

    def create(klass, value)
      klass.new(value)
    end
    
    g = create(Greeting, "Hello")
    g.show

    - 열린 클래스
    언제든지 클래스에 메소드를 추가할 수 있따. 심지어 빌트인 클래스에도 추가할 수 있다.

    class Integer
      def even?
        (self % 2) == 0
      end
    end
    
    p (1..10).select { |n| n.even? }
    # => [2, 4, 6, 8, 10]

    - 싱글턴 객체
    싱글턴 메소드는 클래스가 아닌 개별 객체에 정의될 수 있다.

    class Dog
    end
    
    rover = Dog.new
    fido = Dog.new
    
    def rover.speak
      puts "Red Rover"
    end
    
    rover.speak  # => "Red Rover"
    fido.speak   # => NoMethodError

    - Definition Hooks
    갈고리(Hook)는 사용자가 프로그램 실행 도중 특정 시점에 컨트롤을 가질 수 있게 해준다.

    class MyClass
      def MyClass.method_added(name)
        puts "Adding Method #{name}"
      end
    
      def new_method
        # Yada yada yada
      end
    end
    # => Adding Method new_method

    - 코드 평가

    class Module
      def trace_attr(sym)
        self.module_eval %{
          def #{sym}
    	printf "Accessing %s with value %s\n",
    	  "#{sym}", @#{sym}.inspect
    	@#{sym}
          end
        }
      end
    end
    
    class Dog
      trace_attr :name
      def initialize(string)
        @name = string
      end
    end
    
    Dog.new("Fido").name  # => Accessing name with value "Fido"
This entry was posted in Ruby & Languages and tagged . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

2 Comments

  1. Posted 2007/01/07 at 9:56 pm | Permalink

    slightly_dangerous_methods! 는 결과를 자신에게 적용하는 메서드입니다. ^_^;;

    a=[1,2]
    b=[1,2]
    a = a.reverse
    b.reverse!
    puts a
    puts b

  2. Posted 2007/01/08 at 10:07 am | Permalink

    예. 발상이 참 신선하다고 해야하나요?
    느낌표가 들어가면 결과가 자신에게 반영되기 때문에 사용시 주의해야 하는 메소드 정도로 이해하면 되겠네요.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>