空飛ぶたまごエンジニア

韓国進出を夢見るエンジニアのブログ

JP_Stripes で LT 登壇してきました!

2019年4月26日に開催された JP_Stripes Tokyo Vol.12 に「 Billing でサブスク決済を実装してよかった話」というタイトルで LT 登壇させていただきました。

はじめに

今回の LT は、「 Billing でサブスク決済してよかった話」というタイトルで発表しました。

スライドはこちらです。

この記事は、LT で発表したことを文字で起こした記事となります。要点だけを知りたい方はスライドをご覧ください。

JP_Stripes とは?

JP_Stripes とは、オンライン決済のプラットフォームである Stripe を日本で利用するユーザのコミュニティです。

今回は東京で12回目の開催となるイベントで LT 登壇をさせていただきました。

eventregist.com

JP_Stripes のイベント情報は、 Event Regist で公開されているようです。

発表内容「 Billing でサブスク実装してよかった話」

Billing ってなに?

一言で説明すると「 Stripe が提供している、定期支払いを簡単に実現できる API 」です。

f:id:yamataku3831:20190525130358p:plain
Stripe の公式サイトから引用

詳しい説明は公式サイトをご覧ください。

stripe.com

MVPとして始まったサブスク決済

私が所属する会社のサービスでは、サブスクを提供しています。サブスク実装当初は、 MVP ということもあり、支払い日になったらスタッフが Admin 画面から手動でサブスク継続処理を実行していました。

軌道に乗りはじめ、スタッフから嬉しい悲鳴が...

サブスク機能をリリースしてから、嬉しいことに契約者が増えていきました!

しかし、サブスク契約者が増えるのに比例して、スタッフが手動でサブスク継続処理を実行する手間も増えていきました。

その結果、スタッフから サブスク決済の自動化管理画面のバージョンアップ を求める声があがります。

スタッフの要望に対応するコストの高さ

1. サブスク決済自動化
当時は Stripe ではない他のオンライン決済サービスを使用していました。

そのオンライン決済サービスには、サブスクのサービスが提供されていなかったため、サブスク自動決済機能を実装しようとすると、全て自前で用意する必要がありました。

そのため、対応するコストが非常に高く、判断に迷っていました。

2. 管理画面のバージョンアップ
また一方で、サブスク契約者が増えてきたので、サブスク契約者の予約状況なども管理画面に表示してほしいといった要望も上がりました。

ひとつひとつの要望への対応コストはそこまで高くありませんが、今後要望があがるたびに機能追加していくとなると、メンテナンスコストが高まります。

悩めるエンジニアに決済サービスクローズの追い打ち

スタッフの要望にどう対応しようか悩んでいたある日、当時利用していた決済サービスがクローズするというアナウンスがありました。まさに追い打ち。。

f:id:yamataku3831:20190525140404p:plain

サブスクの自動化や管理画面のバージョンアップ以前に、迅速に他の決済サービスに移行しなければならない という状況になってしまいました。

Stripe との出会いでピンチがチャンスに!

様々なオンライン決済サービスを調査してみたところ、 Stripe を導入すれば悩みの種となっていたサブスク周りの課題も一緒に解決しそうなことがわかり、移行が行われました。

1. サブスク決済自動化
Stripe には Billing というサブスク機能を簡単に実装できる API が提供されているため、 サブスク自動決済機能を自前で用意する必要がなくなりました

2. 管理画面のバージョンアップ
Stripe には高機能な管理画面がすでに準備されているため、 管理画面も自前で用意する必要がなくなりました 。そのおかけで、将来かかったであろう管理画面のメンテナンスコストも実質なくなったことになります。

Stripe と出会ったおかげで、オンライン決済サービスのクローズというピンチを乗り越えただけでなく、これまでの悩みまで解決してしまいました!

f:id:yamataku3831:20190525144907p:plain

まとめ

オンライン決済サービスとして Stripe を導入し、 Billing というサービスを利用したことで サブスク自動決済機能 を自前で用意しなくてよくなっただけでなく、 サブスク契約者の管理画面 も自前で用意してメンテナンスしていく必要もなくなりました。

自前で用意するものがなくなったおかげで、 自分たちのサービスのコアとなる部分の機能開発によりいっそう時間をさけるようになった ということが Stripe の Billing を導入してよかったと思えることです。

Stripe に移行したときのより詳しい話

Stripe に移行したときのより詳しい話については、私が所属するチームのリーダーが記事にまとめていますので、そちらをご覧ください。

tech.kitchhike.com

10月13日の日記

今日の学び

わからなかった単語

ポインタ

変数の一種で、あるオブジェクトの論理的位置情報を格納する変数のこと

参考にしたサイト

リンク

ある構造体のメンバに別のメンバの構造体にアクセスするためのポイントを格納することで、構造体をつなぐことを リンク という。

参考にしたサイト

コレクション

データやオブジェクトなどをまとめて格納するためのデータ構造やクラスなどの総称

配列やハッシュ、スタック、キューもコレクションの例である

参考にしたサイト

10月9日の日記

今日の学び

私の苦手なもの「読解・要約」

今日の学びというと嘘になってしまいますが、週末(10月7・8日)に自分を振り返り、今の私には「読解力・要約力」が足りないと感じました。

相手の伝えたいことをしっかりと理解することが小学生の頃から苦手で、今に至るまで逃げて生きてきました。(今思えば国語の点数はずーーっと悪いままでした)

文字を読むのも苦手ですし、人の話を聞いて「つまり、〜〜〜ということ」と要約するのが苦手です。いつも途中で何について書いているのか、話しているのかわからなくなります。

それが原因で学びの効率も悪くなっている ような気がします。なぜなら、文章を読んで理解するのは苦手だったり、人の話を聞いてまとめることが苦手だったりするからです。

まずは文字アレルギーの克服から!

私は文字と向き合うことから、ほとんど逃げてきました。本も指で数えるほどしか読んだことがありません。(ちょっといいすぎかもw)

しかし、このままでは学べるものも学べず、成長スピードが遅いままです。まずは「文字アレルギー」を克服し、「読解力・要約力」を伸ばして、成長スピードを向上させようと思います!

そこで、先週末に6つの小説を購入しました。いきなり純文学など難しそうな本に挑戦すると、あっという間に挫折しそうだったので、まずはライトな小説から挑戦しようと思いました。

ちなみに私が購入した小説はこちらです。

また、同じ夢を見ていた (双葉文庫)

また、同じ夢を見ていた (双葉文庫)

コンビニ人間 (文春文庫)

コンビニ人間 (文春文庫)

七つの会議 (集英社文庫)

七つの会議 (集英社文庫)

10月6日の日記

今日の学び

リファクタリング: Rubyエディション

Self Encapsulate Field

フィールドとの密結合により、フィールドへの直接アクセスが不都合になっているとき、アクセサを使って関節アクセスするようにする

# リファクタリング前
def salary
  @base_salary * @bonus_rate
end

# リファクタリング後
attr_reader :base_salary, :bonus_rate

def salary
  base_salary * bonus_rate
end

スーパークラスはフィールドに直接アクセスしているが、サブクラスでは計算した値を返すためにフィールドへのアクセスをオーバーライドしたくなったときが絶好のタイミング

class Employee
  attr_accessor :base_salary, :bonus_rate

  def initialize(base_salary, bonus_rate)
    @base_salary = base_salary
    @bonus_rate  = bonus_rate
  end

  def salary
    base_salary * (1 + bonus_rate)
  end
end

class Manager < Employee
  attr_reader :position_allowance

  def initialize(base_salary, bonus_rate, position_allowance)
    super(base_salary, bonus_rate)
    @position_allowance = position_allowance
  end

  def total
    super + position_allowance
  end
end

大事なのは、リファクタリングによって直接変数アクセスも関節変数アクセスにも切り替えることができること。

Change Value to Reference

同値のインスタンスをいくつも生成するクラスがあり、それらのオブジェクトを同じものと判断したいとき、そのオブジェクトを参照オブジェクトに変更する

# リファクタリング前
class Guest
  attr_reader :name

  def initialize(name)
    @name = name
  end
end

guest1 = Guest.new("Bob")
guest2 = Guest.new("Ken")
guest1 == guest2 # => false

# リファクタリング後
class Guest
  attr_reader :name

  def initialize(name)
    @name = name
  end

  Instances ={}

  def self.load_guests
    new("Bob").store
  end

  def store
    Instances[name] = self
  end

  def self.create(name)
    Instances[name]
  end
end

Guest.load_guests
guest1 = Guest.create("Bob")
guest2 = Guest.create("Bob")
guest1 == guest2 # => true

オブジェクト導入時は、イミュータブルな値を持つ単純な値オブジェクトという位置付けだったけれども、後で変更可能なデータが追加したり、概念的に同じオブジェクトを参照する部分に変更による効果を与えたくなる場合がある。

そういった場合に上記のように、ファクトリメソッドを定義し、オブジェクトの作成処理を管理するようにして実装する必要がある。

つまりは、単純な値オブジェクトから参照オブジェクトに変更しなければならないということである。

Change Reference to Value

イミュータブルな参照オブジェクトの管理が面倒になってきたとき、オブジェクトを値オブジェクトに変更するテクニック

# リファクタリング前
class CurrencyRate
  attr_reader :code

  def initialize(code)
    @code = code
  end

  def self.get(code)
    ...レジストリから CurrencyRate インスタンスを返す
  end
end

jpy1 = CurrencyRate.get("JPY")
jpy2 = CurrencyRate.get("JPY")
jpy1 == jpy2

CurrencyRate.new("JPY") == CurrencyRate.new("JPY") # => false
CurrencyRate.new("JPY").eql?(CurrencyRate.new("JPY")) # => false

# リファクタリング後
class CurrencyRate
  attr_reader :code

  def initialize(code)
    @code = code
  end

  def self.get(code)
    ...レジストリから CurrencyRate インスタンスを返す
  end

  def eql?(other)
    self == (other)
  end

  def ==(other)
    other.equal?(self) ||
      (other.instance_of?(self.class) &&
       other.code == code)
  end
end

jpy1 = CurrencyRate.get("JPY")
jpy2 = CurrencyRate.get("JPY")
jpy1 == jpy2

CurrencyRate.new("JPY") == CurrencyRate.new("JPY") # => true
CurrencyRate.new("JPY").eql?(CurrencyRate.new("JPY")) # => true

Change Value to Reference とは全く逆のことをしている。

イミュータブルな参照オブジェクトの管理が面倒になってきた時に、オブジェクトを値オブジェクトに変更することで、管理コストを下げることができる。

しかし、そのためには eql? メソッドと == メソッドをオーバライドする必要があるので、注意が必要。

調べたこと

値オブジェクト

以下のような特徴を持ったオブジェクトを「値オブジェクト」という

  • インスタンス自体よりも、保持するデータ値が重要な意味をもつ。
  • インスタンスが異なっても、同じ値を保持していれば同じオブジェクトとみなす。
  • 必要に応じて自由にコピーを作ることができる。
  • 原則としてイミュータブルでなければならない。

参照オブジェクト

以下のような特徴を持ったオブジェクトを「参照オブジェクト」という

  • インスタンス自身が重要な意味をもつ。
  • 同じデータを持っていても、インスタンスが異なれば違うオブジェクトと見なす。
  • 通常コピーは作らない。
  • イミュータブルでなくてもよい。

10月3日の日記

今日の学び

リファクタリング: Rubyエディション

第7章は オブジェクト間でのメンバの移動 をテーマに、リファクタリングのテクニックがまとめられている。

全部で6つのテクニックが紹介されている。

  • Move Method
  • Move Field
  • Extract Class
  • Inline Class
  • Hide Delegate
  • Remove Middle Man

Move Field

要約

フィールドが、他クラスでよく使われていたら、最もよく使われているクラスにフィールドを移動する

# リファクタリング前
class Employee
  def initialize(bonus_rate)
    @bonus_rate = bonus_rate
  end

  def bonus
    @bonus_rate * base_salary
  end
end

# リファクタリング後
class Employee
  def initialize(employee_type)
    @employee_type = employee_type
  end

  def bonus(base_salary)
    @employee_type.bonus_rate * base_salary
  end
end

class EmployeeType
  attr_accessor :bonus_rate

  def initialize(bonus_rate)
    @bonus_rate = bonus_rate
  end
end

※ 注意: 上記サンプルは、 bonus_rate フィールドが Account クラスではなく AccountType クラスでよく使われるようになることが前提となっている

説明

  • フィールドは最もよく使われているクラスに定義する

備考

  • 以前までは正しかった実装が、今では誤った実装になりうる
    • 仕様が変われば、リファクタリングで実装し直せばいいだけ
    • 問題は誤った実装のまま、何も対策を打たないこと

所感

フィールドは最もよく使われているクラスに定義することで、コード量が減ることを実感。

コード量が少なくなれば、それだけ人間が読むコードの量も減るし、結果的に効率的な開発に繋がるのだろうと思った。

調べたところ

ここでいうフィールドとは?

クラス内のインスタンス変数のことを差すようだった

アクセサ

クラス内にインスタンス変数を定義するだけでは、そのクラスのインスタンスから定義したインスタンス変数にアクセスできない

class Person
  def initialize(name)
    @name = name
  end
end

person = Person.new("Bob")
person.name
# => NoMethodError: undefined method `name' for #<Person:0x00007fd0faaf99e8 @name="Bob">

上記のインスタンス変数にアクセスするためには、以下のようなゲッターとセッターを実装する必要がある

class Person
  def initialize(name)
    @name = name
  end

  # ↓ これがゲッター
  def name
    @name
  end

  # ↓ これがセッター
  def name=(val)
    @name = val
  end
end

person = Person.new("Bob")
person.name
# => "Bob"

person.name = "John"
person.name
# => "John"

Ruby には attr_readerattr_writerattr_accessor といったアクセスメソッドが用意されていて、ゲッターとセッターを簡単に実装できる

定義式 機能
attr_reader: 変数名 参照が可能
attr_writer :変数名 更新が可能
attr_accessor :変数名 参照と更新が可能
class Person
  attr_accessor :name

  def initialize(name)
    @name = name
  end
end

person = Person.new("Bob")
person.name
# => "Bob"

person.name = "John"
person.name
# => "John"

10月1日の日記

今日の学び

リファクタリング: Rubyエディション

第7章は オブジェクト間でのメンバの移動 をテーマに、リファクタリングのテクニックがまとめられている。

全部で6つのテクニックが紹介されている。

  • Move Method
  • Move Field
  • Extract Class
  • Inline Class
  • Hide Delegate
  • Remove Middle Man

Move Method

要約

メソッドが、他クラスの機能を多く使っていたり、他クラスに何度も利用されたりしていたら、最もよく使われているクラスにメソッドを移動する

# リファクタリング前
class Employee
  def base_salary
    if @employee_type.manager?
      return 200000
    else
      return 100000
    end
  end
end

# リファクタリング後
class EmployeeType
  def base_salary
    if manager?
      return 200000
    else
      return 100000
    end
  end
end

説明

  • メソッドは最もよく使われているクラスに定義する
    • 他クラスを参照しなくて済むので、コードが少なくなる
    • 他クラスの実装を見に行かなくてよくなる

備考

  • リファクタリングをしたら、必ずテストを実行する
    • メソッドを移動したときにテストを実行
    • 上記に伴うメソッド呼び出し箇所の書き換えでもテストを実行
    • Rubyコンパイラ言語ではないので、テストが命綱になる

所感

メソッドは、最もよく使われているクラスに定義するということを、恥かしながら最近知った。

しっかり考えればわかることではあるが、他クラスのオブジェクトを参照しなくてもよくなるし、他クラスの実装も見に行ったりしなくてよくなる。結果的に効率よくコードがかけるようになるなと実感した。

また Rubyインタープリタ言語であり、リファクタリング後にコンパイルによってミスをキャッチできない。だからこそ、テストが重要であるということに深く納得した。

タスクを効率よく進めるために改めようと思った3つの考え方

背景

私はタスクの進捗が遅いことに課題を感じていて、それを解決するために我流でどうにかしようとしていました。

しかし、それだと効率も悪く、なかなか根本的な解決に繋がらないことを実感していたので、他の方の知恵を借りようと本を読むことにしました。

テーマが似た本を3冊を読んだところ、仕事が遅い人の特徴で共通して挙げられているものがいくつかありました。

私自身思い当たる節があったので、今の私の考え方で改めるべきだと感じたものついてまとめてみました。

読んだ本

今回参考にさせていただいた本は以下の3冊です。

「仕事が速い人」と「仕事が遅い人」の習慣 (アスカビジネス)

「仕事が速い人」と「仕事が遅い人」の習慣 (アスカビジネス)

「すぐやる人」と「やれない人」の習慣 (アスカビジネス)

「すぐやる人」と「やれない人」の習慣 (アスカビジネス)

図解 2割に集中して結果を出す習慣術 ハンディ版

図解 2割に集中して結果を出す習慣術 ハンディ版

ひとつのことに集中する

課題となる考え方

1つ目は、 複数のことを一度にこなそうという考え方 です。

私は目の前のタスクに、なかなか集中することができません。

なぜなら目の前のタスク以外のこと(調査や雑務など)もこなそうと、様々なことに気を取られてしまうからです。例えば、以下のようなことです。

  • Slack に調査が必要な要件が流れてくると気を取られてしまう
  • 社内で困っている内容の話を耳にすると一緒に解決しようとしてしまう
  • 自分より先輩のメンバーに雑務をさせまいと常に周りを見てしまっている

具体的な解決方法

シングルタスク

集中をするには、シングルタスクを行うとよいそうです。

シングルタスクとは、 一度にひとつの作業に集中すること を指し、生産性をあげることを目的としています。

複数のタスクを一度に進めようとすると、タスク・スイッチングで空白の時間が発生してしまい、一説によると生産性を 40% も下げてしまうとのことでした。

f:id:yamataku3831:20180908193351p:plain

シングルタスクに関する本も出ていたので、せひご覧ください。

SINGLE TASK 一点集中術――「シングルタスクの原則」ですべての成果が最大になる

SINGLE TASK 一点集中術――「シングルタスクの原則」ですべての成果が最大になる

誘惑を遮断する

もうひとつは、気を取られそうな誘惑を物理的に遮断することです。

誘惑と戦おうとするとそれだけでパワーを使いますし、戦った時点で目の前のタスクに100%集中できているとは言えません。

誘惑と戦うよりも誘惑から物理的に遮断する方が効率的です。例えば、

  • 目の前のタスクが終わるまで Slack を閉じる
  • 集中できる音楽を聞いて、雑音を遮断する
  • 他のメンバーの動きが目に入らない環境で仕事をする

といったことを習慣にすると良いかもしれないですね。

仕事の時間は有限であると意識する

課題となる考え方

2つ目は、 寝なければいくらでも時間はあるという考え方 です。

私はあまり寝なくても頑張って働ける体質(だと思っていた)なので、時間はいくらでもあると考えてしまっていました。

そのせいか明確な時間制限を設けずにタスクに取り組んでしまい、結果的にだらだらとタスクに取り組んでいました。

具体的な解決方法

制限時間を設けてタスクに取り組む

時間制限を設けてタスクに取り組むことで、半ば強制的に集中を余儀なくされます。

時間の強制力をうまく活用して、瞬発力を引き出すことが大切です。

プライベートを充実させる

プライベートな時間にやりたいことがあれば、定時までに仕事を終わらせようという力がはたらきます。

プライベートが充実していればいるほど、その力も大きくなります。

まずは没頭できる趣味などを見つけることが良いのかもしれませんね!

体と脳のコンディションを意識する

課題となる考え方

3つ目は、 体や脳のコンディションが悪くても、気合いと体力でカバーするという考え方 です。

睡眠時間が少ないと、頭の中に霧が張っているような感覚になって集中ができないとわかっているのに、それは甘えだと長時間労働でカバーしていました。

これだといつまでたっても、タスクを効率よくこなせないですよね。負のスパイラルです。

具体的な解決方法

脳の性質に合わせて取り組むタスクを変える

人間は朝起きてから2, 3時間あたりでもっとも効率的に脳が動くようなので、その時間帯に合わせて重要な課題やクリエイティブな仕事に取り組むと良いそうです。

逆に夜は脳も体も疲れ切っているので、単純作業をするのに適しているとのことでした。

脳の性質に合わせて取り組むタスクを変えると効率的に仕事が進められそうですね。

戦略的に睡眠をとる

遅く起床してしまい、もっとも効率的に脳が動くタイミングが、お昼ご飯の時間と重なってしまっては勿体無いですよね。

何時に就寝すれば良いかを逆算する必要があります。

また人間は基本的に睡眠時間が6時間未満になると、意志力が低下し、誘惑に負ける可能性を高めてしまうそうです。

つまり、効率よくタスクをこなすには、戦略的に睡眠をとるべきだということでした。

まとめ

上記の3つに共通するのは、 仕組みを作って頑張らずに課題を解決する というアプローチの仕方ではないでしょうか。

私はこれまでの人生、多くの課題を根性で乗り切ってきたので、根本的に考え方を変える良いきっかけになりました。

もし私と同じようなことで悩んでいる方がいましたら、今回紹介した3冊の本を読んでみてください。

私と同様に今までの悩みや問題が解決できるきっかけになるかもしれません。