Ryo | Web developer blog

Web開発者のブログです。

ダック・タイピングを例に動的型付け言語と静的型付け言語の違い

ダック・タイピングとは
If it walks like a duck and quacks like a duck, it must be a duck.  
(もしも、それがアヒルのように歩き、アヒルのように鳴くのなら、それはアヒルに違いない。)  
                                デーブ・トーマスより

ダック・タイピングは、オブジェクトに何ができるかはオブジェクトそのものが決定します。静的型付け言語と違って継承関係が無く、オブジェクトがインタフェースのすべてのメソッドを持っている場合には、対象のクラスがインタフェースを宣言的に実装していない場合でもオブジェクトを呼び出すことができます。

Rubyを使ったコード例
class Duck
  def sound
    "Quack"
  end
end

class Cat
  def sound
    "Meow"
  end
end

def sound(object)
  object.sound
end

puts sound(Duck.new)
puts sound(Cat.new)

soundメソッドはオブジェクトにsoundメソッドが定義されているのかを確認できませんが実行時には呼び出すことが出来ます。

Javaでインタフェースを使って、同様の出力結果になるコード例
// Animal.java
package com.ry0takahash1;

public interface Animal {
    public abstract String sound();
}

// Duck.java
package com.ry0takahash1;

public class Duck implements Animal {
    public String sound() {
        return "Quack";
    }
}

// Cat.java
package com.ry0takahash1;

public class Cat implements Animal {
    public String sound() {
        return "Meow";
    }
}

// Main.java
package com.ry0takahash1;

public class Main {
    public static void main(String[] args) {
        Duck duck = new Duck();
        System.out.println(duck.sound());

        Cat cat = new Cat();
        System.out.println(cat.sound());
    }
}

インタフェースで、あらかじめメソッドを宣言しているため実行しなくてもsoundメソッドが定義されていることが明示的に分かります。

まとめ

ダック・タイピングを例に動的型付け言語と静的型付け言語の違いを考えてみました。個人的には個人開発や小規模なチームでの開発であれば動的型付け言語、大規模なチームでの開発であれば静的型付け言語を使うかなと思います。適材適所でプログラミング言語の使い分けが出来ると良いですね!

ES6とReactとVue.jsの基礎を学ぶ

JavaScriptの勉強

最近、JavaScriptを中心に勉強しています。業務ではVue.jsを使っていますが、Reactにも興味があり少しずつコードを書き始めました。ReactはSimple、Vue.jsはEasyと言われておりますが、その意味も理解できるようになってきました。私は下記のサイトを参考に勉強をしました。

順番的にはJavaScript PrimerでES6を学んでからReactのチュートリアルをやってみるとパターンが似ており、分かりやすいと思います。

コードの比較

ES6では以下のような書き方がベースになります。(処理の中身は省略しています。)

export class App {
  constructor() {
  }

  handleAdd(title) {
  }

  handleUpdate({ id, completed }) {
  }

  handleDelete({ id }) {
  }

  handleSubmit(event) {
  }

  handleChange() {
  }

  mount() {
  }

  unmount () {
  }
}

Reactは、このような書き方です。ES6での書き方と似ています。(処理の中身は省略しています。)

class Game extends React.Component {
  constructor(props) {
    super(props);
    this.state = {};
  }

  handleClick(i) {
  }

  render() {
    const history = this.state.history;
    return (
      <div className="game">
      </div>
    );
  }
}

また、DOMを返すだけの場合はAllow Functionベースで書くこともできます。

const Square = (props) => (
  <button className="square" onClick={props.onClick}>
    {props.value}
  </button>
);

そして、Vue.jsでは単一ファイルコンポーネントで書きます。(処理の中身は省略しています。)

<template>
</template>

<script>
export default {
  data () {
    return {
    }
  },
  methods: {
  }
};
</script>

<style scoped>
</style>

ES6やReactはオブジェクト指向のクラスという仕組みに近いですが、Vue.jsはメソッドを多く定義していくようなイメージです。どの書き方が良いかは好みの問題かと思いますが、個人的にはReactの書き方が好きです。実際に業務で使うとなるとRestAPIを呼び出すために、axiosライブラリを利用したり、GraphQLAPIを呼び出すためにApolloが提供しているライブラリを利用しますが、 複雑さが増していくとVue.jsの単一ファイルコンポーネントの書き方では行数が増えてしまい、少し見づらくなってきます。SPAを本格的に実装するときは、やっぱりReactの方が優れているかなと最近、感じています。

余談

しかし、フロントエンドの領域も様々な仕組みやベストプラクティスが蓄積されてきており、難しくなってきたなと感じています。 数年前までは控えめなJavaScriptが主流でしたし、少しjQueryとかが書けるだけで一般的なシステムの開発が出来ていました。技術の進歩は嬉しいですが、追いつくのもひと苦労ですね。

Ruby2.7.0_Rails6.0.3.2で表示される警告の解決方法

アップグレードした話

会社でRuby on Rails(APIモード)のアップグレードを行いました。アップグレードの目的はActive Storageの機能を使ってAWS S3にデータを保管する仕組みを構築するためです。アップレードにあたっては以下のガイドや記事が参考になり、とても感謝しています。

私が担当しているシステムではRSpecを使ってユニットテストを書いていますが、Railsを5.1から6.0に上げるにあたって何度もユニットテストを実行しながら、こまめに確認することでアップグレードの作業自体は1日程度で完了させることができました。(RSpecなので並列テストの機能が使えないのが、ちょっと悲しいです。)しかし、こういう機会を経験してみて改めてユニットテストを書いておいて良かったなと思います。「テストを書く時間が無いのではなく、テストを書かないから時間が無くなるんだ」という名言は本当だなと実感しています。苦労しながらも書いた成果がありました。
さらに、Rubyのバージョンも2.5から2.7に上げることができ、新しい仕組みを使えることができるので今後が楽しみです。

Ruby2.7.0_Rails6.0.3.2で表示される警告の解決方法

さて、そういえば自宅の開発環境は古いままだったなと最近、気付いてアップグレードを行いました。そして、試しにrails newをしてみて色々と確認してみたら、初めの簡単な操作で警告が表示されるようになっていました。はい、主にRuby2.7の影響です。修正版のライブラリがRubyGems.org経由での配布に、まだ対応されていないようですので解決方法を記事にしたいと思います。

今回、試したバージョンは以下のとおりです。

Ruby on Railsのプロジェクトを新規に作成します。

$ rails new sample-app

試しにscaffoldで確認用のエンティティを作成して確認します。

$ rails g scaffold book code:string name:string

DB作成、マイグレーションを行います。

$ rails db:create
$ rails db:migrate

テストを実行します。

$ rails test

テストの実行ログに以下の警告が出力されます。

sprockets-rails-3.2.1/lib/sprockets/rails/helper.rb:355: warning: Using the last argument as keyword parameters is deprecated; maybe ** should be added to the call
sprockets-4.0.2/lib/sprockets/base.rb:118: warning: The called method `[]' is defined here

該当の箇所を確認してみます。

# sprockets-rails-3.2.1/lib/sprockets/rails/helper.rb:355
def find_asset(path, options = {})
  @env[path, options]
end

該当の「sprockets-rails」ライブラリのリポジトリを確認すると、すでに対応されています。

sprockets-rails/helper.rb at master · rails/sprockets-rails

これは、Ruby 2.7で位置引数とキーワード引数の処理方法が変更されたのが原因になります。Ruby 3へのスムーズな移行を提供することを目的とした変更のようです。しかし、以下のIssueで議論されているとおり、gemのリリースが行われていないようです。

Ruby 2.7 deprecation warning · Issue #659 · rails/sprockets

解決方法はIssueに記載されていますが、Gemfileにgithub経由でライブラリをダウンロードするように変更すると解決できます。

# Gemfile
gem "sprockets-rails", github: "rails/sprockets-rails"

ライブラリをインストールして、テストを実行すると、警告は表示されなくなりました。

$ bundle install
$ rails test
余談

2年前のRailsではWebpackerが毎回ビルドしていたのですが、最新のRailsではビルドされなくなっているのが地味に嬉しいです。以下のログが表示されるだけです。

[Webpacker] Everything's up-to-date. Nothing to do

開発体験が向上されています!OSSの文化って素晴らしいですね。何もしなくても改善され続けているなんて、とてもクールです。