1. **동적 타이핑**:
Ruby는 동적 타이핑을 채택하고 있습니다. 이는 변수의 타입을 명시하지 않고도 사용할 수 있다는 의미입니다. 이러한 유연성 때문에 시간 절약이나 코드 간결성의 장점을 얻을 수 있지만, 대형 프로그램에서는 타입 오류를 쉽게 잡아내기 어렵습니다.
```ruby
def add(a, b)
a + b
end
puts add(1, 2) # 출력: 3
puts add("1", 2) # 오류 발생: String can't be coerced into Integer
```
2. **메소드의 직접적인 변경 가능**:
Ruby는 메소드를 열고 직접 재정의할 수 있는 능력을 제공합니다. 'Monkey Patching'이라고도 불리는 이 방법은 때때로 유용하지만, 사용자가 클래스 및 모듈의 기존 메소드를 덮어쓸 위험이 있어 코드의 예측 가능성을 떨어뜨립니다.
```ruby
class Integer
def +(other)
self - other
end
end
puts 1 + 2 # 출력: -1
```
3. **명령어 열거**:
Ruby는 내장 함수와 문법적 설탕이 많아 같은 작업을 다양한 방법으로 수행할 수 있습니다. 이는 강력한 기능을 제공하지만, 서로 다른 스타일의 코드가 한 프로젝트에서 섞일 수 있는 경우 코드 가독성과 유지보수성을 저하시킬 수 있습니다.
```ruby
numbers = [1, 2, 3, 4, 5]
# 여러 방식의 요소 합
sum1 = numbers.inject(:+)
sum2 = numbers.reduce { |sum, n| sum + n }
sum3 = numbers.sum
puts sum1 # 출력: 15
puts sum2 # 출력: 15
puts sum3 # 출력: 15
```
4. **모듈과 믹스인**:
Ruby는 다중 상속을 허용하지 않는 대신 믹스인을 통해 문제를 해결합니다. 모듈을 사용하여 믹스인을 구현하는 이 방법은 강력하지만, 클래스의 구조가 복잡해질 수 있고, 메소드 이름 충돌 등의 문제가 발생할 수 있습니다.
```ruby
module Swimmable
def swim
"Swimming!"
end
end
class Animal
end
class Fish < Animal
include Swimmable
end
fish = Fish.new
puts fish.swim # 출력: Swimming!
```
Ruby는 많은 자유도를 제공하는 언어로 이러한 자유도는 강력한 도구가 될 수 있지만, 기초를 확고히 하지 않고 무턱대고 사용하면 복잡한 문제에 직면할 수 있습니다. 올바른 학습과 경험을 통해 이러한 난관을 극복하고 Ruby의 진정한 장점을 활용할 수 있습니다.