8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

CrystalAdvent Calendar 2016

Day 5

Rubyで作っていたプログラムをCrystal Langに置き換えてみた

Posted at

というお話です。

tr;dl

  • 担当してるプロジェクトのRailsアプリがメモリ肥大化してるしレスポンス遅くて大変
  • メンバーでどうしようかと話が出ている中で、「一部切り出して別プログラムにしてみては?」と提案されたよ
  • そのときCrystalを推している人がいて、Rubyからコンバートしやすいんじゃね?という話からとりあえずやってみたよ
  • やってみたらやはり厳しい箇所はある、がモノを選べば意外と苦戦はしなかった
  • いろいろあって本番投入は見送ったけど、考え方としてはありだと思う

経緯

わたくし、ここでお仕事しておりますが、現在担当しているプロジェクトにおいて開発・保守をしているRailsアプリにおいて、以下のような問題がありまして、それはそれはメンバーを悩ませていました。

  • レスポンスが遅い。
    • 特にこのRailsアプリは数多くの帳票を出力することが求められていて、特に大量データ出すやつがつらい
  • メモリめっちゃ食う
    • 一回でかい帳票を作ると肥大化したままになって大変

上に書いた問題から誘発されてさらに問題が起こったりして、運用で非常に手のかかる子になっていたのでした。

そこでいくつか改善していく方策をうっていきました。そのうちの一つに、「帳票を作る箇所を別プロセスにすりゃいいのでは?」という提案があり、そこでメンバーでCrystalを推していた人がいたのでとりあえず使ってみましょう、という話になったのでした。やっぱり型がほしいのです。

ちなみに自分が担当したのは、Crystalは自分も興味があってちょっと触っていたので、そこで手を上げたというのが経緯です。

実際やってみたどうだったか

手を上げてみて取りかかったはよいものの、基本的にそのまま動くことはありえないと思っていて実際にその通りでした。ActiveRecordがバリバリ使われている箇所は非常に厳しい。こんがらがったscopeをひもといてCrystalで扱えるようなかたちに落とし込む必要がありました。

そのため、今回はSQLで直接データを取り出すかたちで作られていたRubyのコードをCrystalにコンバートするようにしました。さらにライブラリとしてはwaterlink/crystal-mysqlを使用しています。

元コードの設計としてはSqlLoaderクラスをベースクラスとして、それを継承したExsampleLoaderクラスを実装してそこでSQLでデータ取得、データの加工を行うようにしてたが、Crystalではデータ取得と加工を別クラスにわけました。おおよそで書くとこんな感じです。Rubyから簡単にConvertしたので型が書かれてなくて寂しい感じですね。

# coding: utf-8
require "mysql"

module Loader
  class SqlLoader
    def initialize
      @conn = MySQL.connect("exsample.com", "user", "password", "db_name", 3306_u16, nil)
      @conn.set_option(LibMySQL::MySQLOption::MYSQL_SET_CHARSET_NAME, "utf8")
      @conn.query(%{SET NAMES utf8})
    end

    def datas
      datas = @conn.query(sql)
      if datas
        datas
      else
        nil
      end
    end

    private def sql
    end
  end

  class ExsampleLoader
    private def sql
      # この中でSQLを書く、大変………
    end
  end
end

class Exsample
  def initialize(loader)
    @loader = loader
  end
 
  # この下に加工するメソッド書いたりする
end

上記Crystalで書いたものは一つのバイナリにして、Rails側から呼び出すかたちにしました。全体の実装自体はそれほど複雑ではなかったのですが、crystal-mysqlの挙動に悩まされたりして意図した動きになるのに2日ほどかかりました。

見送り理由

という感じで一通り実装してみたものの、2016/12/03時点では本番に投入していません。理由いくつかありますが、技術的な面で行くと

  • Crystal自体がどんどん開発進んでいて、そこに追従していくコストが今は厳しい
    • 現状は外部ライブラリの安定感とかそういうところが、プロダクションでは若干つらい
  • 今はcapistranoでデプロイしてるけど、ビルドとかもどうせなら自動化したいしそういうことも考える必要があるけど、今はあんまり暇がない

というところですね。とはいえそこらあたりのコストを払えるのであれば、Ruby知ってる人は違いを押さえられれば他の言語覚えるより楽な感じもするし、投資する先の選択肢としてありな感じはします。

8
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?