ls /asapon/blog

基本tech、時々多趣味

転職して1年と半年が経ったので、ざっくり振り返ってみた

はじめに

今年9月で転職して、1年半が経ちました。書きたいことはたくさんあるのですが、現職で何をやっているか踏まえながら、YWTで今日までをざっくり振り返ってみたいと思います。

現職では何をやっているの

株式会社フィードフォースで、DF PLUSのバックエンドエンジニアとして仕事をしています。
DF PLUSは、お客様からお預かりした商品・人材等のマスタを、GoogleFacebookIndeedを代表するような、検索エンジン・ダイナミック広告・ポータルサイトなどへ広告配信できるアウトソーシングサービスです。デジタルマーケティングでは今や欠かせないデータフィードサービスを、日々開発・改善・運用しています。
バックエンドエンジニアを名乗ってはいますが、DF PLUSではサービスに関わる技術全てに責任を持っています。そのため、インフラ・バックエンド・フロントエンドといったカテゴリに縛られず、要件ごとに必要な知識・経験を総動員する対応力が求められています。

YWTで振り返り

Y(やったこと)

  • 説明能力・思考の言語化ができるようになってきた
    • アウトプットを定期的にすることで、力が身についてきたと感じています
  • 自分が今までやってきたことを、定期的に振り返るようになった
    • 1on1で短期的な振り返りをするようになり、それが長期的な振り返りに生きるようになった
  • データフィード事業がどのようなものか理解できた
  • 原因が分からず放置されていた問題を解決した
    • 「開かずの間」になっていたIssueを解決できたのは、大きな自信になりました
  • 運用に関わる技術・経験を一通り取得し、サービスを動かし続ける自信を得た
    • 1つの技術領域に縛られず、サービスを運用する力がついた
  • 対応できる技術の幅が広がった
  • 前職はスキルアップが止まっている感覚だったが、ここで再び成長することができた
  • ファシリテートの経験も少しずつ積んでいる
    • 前職では受け身の姿勢で仕事をしていたが、現職では現場主導でより良くなるよう動いている

W(分かったこと)

  • 言語化する作業を今までサボり続けていた...
    • 転職当初は考えを上手く伝えられないことが多かった
    • 相手の背景(配属や職種など)を意識することが、自然にできるようになった
  • フルスタックに技術に関わっていく自信が持てた
  • 要件を技術まで落とし込む作業は、どんどん経験を積んでいく必要がある
    • 要件定義は、現在進行形で経験を積んでいるところ
  • バッチ周りの技術・ジョブキューの扱いは詳しくなったが、Web開発の経験不足感はある
  • 自分がどういうエンジニアになりたいのか、まだ模索中
    • 理想としているイメージはできつつある

T(Tryすること)

  • いちエンジニアとして、ちゃんと独立できるようになる。今はなりつつある段階
  • 自分の強みや武器を手に入れたい
    • もともと自分はバランス型なので、尖った特徴があるわけではない
    • バランス型を極める?
  • チーム内外に情報を発信できるようにする
    • ブログも情報発信の練習

思い返してみて

濃厚な1年半を過ごしていると感じました。
私の理想は「運用に関わる技術全てに、正しい理解を持てている」ことなのですが、この理想に近づいている実感があります。「運用に関わる技術全てに、正しい理解を持つこと」は、以下の状態であると考えています。

  • サービスの仕組みを、隙なく把握できている。
  • 今の仕組みに至った経緯を、正しく汲み取ることができる。
  • 対処すべき問題に、様々な角度から手段を講じることができる。転じて、最善策を見つける可能性が高くなる。

この理想を目指している理由は、自分のことをスペシャリストタイプではなく、バランスタイプだと考えたからです。そのため、拘った技術指向よりは「サービスが成長し続けていくために、様々なレイヤーから考え策を講じていく」力を付けていきたいと考えています。たとえスペシャリストほどではなくとも、技術の要所を理解していれば、俯瞰した目線でIssue度の高い改善を進めていくことができると信じています。

これからやっていきたいこと

先の内容の通り、「運用に関わる技術全てに、正しい理解を持てている」ことへ向かって頑張っていこうと考えています。 矛先としては

といった内容で考えています。抽象的なものばかりですが、つまるところ「何年経っても大きくは変わらないであろう、確かな基礎作り」をイメージしています。これは新しい技術に追随する意思がないような、ネガティブな印象を与えるかもしれません。ですが実際は、新しい技術がでてきても、要所を抑えられるような知識・経験を積んでいきたいといったポジティブなものです。
日進月歩の世界で、新しい技術の勘所を素早く抑えることができれば、チャンレンジできることも多くなると思います。すぐに仕事の成果に繋がるものではないかもしれませんが、将来必ず生きてくると考え勉強していきたいと思います!

Rubyで競技プログラミング bit演算の基礎まとめ

はじめに

最近、競技プログラミングの勉強をはじめました。仕事で求められるものとはまた違った知識・経験が要求され、なかなか難しさを感じています。
この記事では競技プログラミングを通して学んだ、Rubyを用いたbit演算の基礎をまとめたいと思います。

bit演算の基礎

表示

0b を先頭につけることで2進数表示にできます。

irb(main):> bit = 0b101
irb(main):> bit
=> 5

論理回路

& は積(AND)、| は和(OR)、~は否定(NOT)、 ^排他的論理和(XOR)を示します。

irb(main):> bit = 0b101 # 10進数では5
irb(main):> another_bit = 0b111 # 10進数では7
irb(main):> bit & another_bit
=> 5 # 0b101
irb(main):> bit | another_bit
=> 7 # 0b111
irb(main):> ~bit
=> -6 # 0b..1010 # 右3桁が010の反転bit
irb(main):> bit ^ another_bit
=> 2 # 0b010

シフト演算

>> で右論理シフト、 << で左論理シフトです。右論理シフトは1/2n倍され、左論理シフトは2n倍されます。

irb(main):> bit = 0b101 # 10進数では5
irb(main):> bit >> 1 # 余りは切り捨て
=> 2 # 0b010
irb(main):> bit << 1
=> 10 # 0b1010

フラグ管理

フラグを立てるときは | を、フラグを下ろすときは ~& を使います。

# フラグを立てる
irb(main):> bit = 0b000
irb(main):> bit
=> 0
irb(main):> bit >> 0 | 1
=> 1
irb(main):> bit >> 1 | 1
=> 1
irb(main):> bit >> 2 | 1
=> 1
# フラグを下ろす
irb(main):> another_bit = 0b111
irb(main):> ~another_bit >> 0 & 1
=> 0
irb(main):> ~another_bit >> 1 & 1
=> 0
irb(main):> ~another_bit >> 2 & 1
=> 0

フラグの有無

先程の右論理シフトを使うことで、右からそれぞれの桁の値を見ることができます。
またフラグの有無を調べるとき気をつけることは、Rubyは0, 1どちらもtrue判定になるので、必ず1かどうか確認する必要があります。

irb(main):> bit = 0b101
irb(main):> bit >> 0 & 1
=> 1 # 0番目は1なので 1 & 1
irb(main):> bit >> 1 & 1
=> 0 # 1番目は0なので 0 & 1
irb(main):> bit >> 2 & 1
=> 1 # 2番目は1なので 1 & 1
irb(main):> bit >> 0 & 1 == 1
=> true # 1だったらtrue, 0ならfalse

bit全探索

最後にbit全探索です。
下のコードを説明すると、 1<<3 は計算量O(2n) より 23 となるので、 8回繰り返すことになります。0 <= i <= 7をprintf("%03b\n", i) で2進数表記にして表示しています。
こうすることで、フラグ有無の全組み合わせを試すことができるようになります。

irb(main):115:0> (1 << 3).times { |i| printf("%03b\n", i) }
000
001
010
011
100
101
110
111

おわりに

bit全探索は頻出問題ですが、ちゃんと勉強しないと取っ付きにくい分野だと思いました。 ただ、解き方に慣れればあとはただの全探索なので、競技プログラミングの最初の壁といった感覚ですね。
次はDPの慣れを増やしていきたい。

RSpecで書く基底クラスのテスト実践例

これはなにか

RSpecを書くときに役立つ、実践例を書いた記事です。今回は

  • 基底クラス

のテストを、改善前と改善後合わせて紹介します。他テスト(Minitestや他プログラミング言語)でも応用できる考え方なので、参考にしてみてください。

基底クラスをテストする

クラス例は以下の base.rb になります。
それぞれのメソッドは

  • #greet
    • 継承先で実装される想定
    • ここでは NotImplementedError をraiseするだけ
  • #default_language
    • 初期値は :ja
    • 継承先の必要に応じてオーバーライドされる

といった単純なものになっています。
このクラスをどのようにテストするか考えていきます。

# base.rb

class Base
  def initialize; end

  def greet
    raise NotImplementedError
  end

  def default_language
    :ja
  end
end

改善前

普通に実装すると以下のようになると思います。
やっていることは Base クラスをインスタンス化し、それぞれのメソッドをテストしているだけです。

# base_spec.rb

require_relative '../base'
require 'spec_helper'

RSpec.describe Base do
  let(:baes) { described_class.new }

  describe '#greet' do
    it 'raises NotImplementedError' do
      expect { baes.greet }.to raise_error(NotImplementedError)
    end
  end

  describe '#default_language' do
    it 'returns :ja' do
      expect(baes.default_language).to eq :ja
    end
  end
end

このテストの改善点

このテストには気になる点があります。それは

Baseクラスそのものをインスタンス化している

いう点です。
本来Baseクラスは、継承先で使われることを想定して作られているはずです。そのため、Baseクラスそのものをインスタンス化するといった使われ方は想定しておらず、実態とは異なる使い方でテストしていることになります。
基底クラスをテストするときは、安直にインスタンス化せず、継承させたあとにテストするべきです。

改善後

下が改善した基底クラスのテストになります。ポイントは

  • Class.#new で派生クラスを作っている
  • 派生クラスをインスタンス化し、メソッドを呼んでいる

という点です。
派生クラスはClassを利用しています。これで簡単に、ガワになる継承先を作ることができました。
また、オーバーライド後の動作も確認できるように

  • when #default_language is overrided to :en

といったテストも作ることができました。より実践に沿った、テストケースになったと思います。

# base_spec.rb

require_relative '../base'
require 'spec_helper'

RSpec.describe Base do
  let(:child_class) do
    Class.new(described_class)
  end
  let(:child_class_instance) { child_class.new }

  describe '#greet' do
    it 'raises NotImplementedError' do
      expect { child_class_instance.greet }.to raise_error(NotImplementedError)
    end
  end

  describe '#default_language' do
    it 'returns :ja' do
      expect(child_class_instance.default_language).to eq :ja
    end

    context 'when #default_language is overrided to :en' do
      let(:child_class) do
        Class.new(described_class) do
          def default_language
            :en
          end
        end
      end

      it 'returns :en' do
        expect(child_class_instance.default_language).to eq :en
      end
    end
  end
end