LiBz Tech Blog

LiBの開発者ブログ

入社2か月間で駆け出しエンジニアがつまずいた15のポイント

目次

初めに

f:id:taisuke_i:20181212170233p:plain

LiBで未経験からWebエンジニアとして働き約2ヶ月程が経過しました!磯部といいます! それまでプログラミングは少し趣味で触るくらいで、実際に現場でがっつりやってみると、 想定はしていたけど色々なギャップがあり、楽しみながらも四苦八苦しています。

2ヶ月前を思い返すと、未経験な状態からWebエンジニアとして実務をする前って分からないこと自体が分からない状態なので、 何を準備したらいいのか、ググることもうまくできずとても不安でした。

受け入れて頂いた職場の先輩方も、未経験者はいったい何を知らなくて何を教えたらいいのか、 困惑していたのではないかと思います。みんな最初は未経験ですが、 慣れるとその頃の悩みとかって思い出せなくなっているのではないかと。

これからWebエンジニアになる人、なりたい人とか、 先輩エンジニアになるかもしれない人の参考になればと思い 2ヶ月時点のリアルな体験としてもっと早く学んでおけば捗ったなーっということを いくつかピックアップして書こうと思います!

共通のつまずき

メソッドを作るのが怖い

実際のプロダクトのコードを変更するのは、 レビューしてもらうのは分かっていても不安でした。(今もですが)

特にメソッド作ったり、何かを+するのは、綺麗なものを汚してる感覚になり抵抗感があります。 そんな状態なので、なるべくメソッド作らないように、 そっと既存のメソッドに付け足したりしてお茶を濁してました。

そんなことをしていると、レビューでメソッドに分けた方が良いよーとコメントを貰いました。 その時なるほどなと思ったのが「メソッドはコードに名前をつける作業」だと考えることです。

メソッドを追加する基準には色々と議論があると思いますが、 一旦駆け出しとしては、名前をつけられそうなロジックの塊があったら、メソッドにする。 と決めてから何より迷うポイントが減ったので気持ち的に楽になりました。

参考になりそうな記事:

関数・メソッドの行数を短く保つと色々と捗る件 - Qiita

Java - 1度しか使わないメソッドは作る必要ありますか。|teratail

データの削除って、データ消すって意味じゃないんですか?

データの削除=データベースからレコードを削除する。

そんなの当たり前じゃん、むしろ他にあるの?と思ってました。 データの削除にも論理削除と物理削除というのがあるらしいです。

物理削除: 駆け出しエンジニアのいわゆる削除 データベースからレコードを物理的に削除する

論理削除: たとえば、

id mail deleted_flag
1 hoge false(削除されていない)
2 fuga true((削除されてる)

のように レコードにdeleted_flagなどのカラムを用意して、 trueだったら削除されている、falseだったら削除されてない、 として扱う概念でした。

現場には削除は削除でも論理と物理がありました。

謎の呪文 後置if、早期リターン、三項演算子

プログラミング入門系の本では出てこないけど、現場では毎日目にするやつでした。 書き方が特殊なので記法を知らないと謎の呪文です。

逆にここが分かるようになると詰まりポイントが減ってコードを読むのが楽になりました。そのくらい結構な頻度で出てきます。

後置if

return true if is_string(x)

駆け出しエンジニアの頭の中では、ifは行頭に出てくるものです。 上記みたいにifが突然出てくると大変混乱するのですが、見かけない日はありません!

後置ifという実行する処理を先に書いて、条件を後に書く記法だそうです。 いつものifに変換するとこんな感じです。

if is_string(x)
  return true
end

突然ifが出てきたら、後置ifでググるときっと解決するはずです

後置if - Google 検索

早期リターン

def hoge?(value)
  return false if value.nil?
  return false if value == hoge
  return false if value == fuga
  # 何かしらの処理
end

こんな感じでメソッドの前半にやたらリターンしてたらそれはきっと早期リターンです! 変数がnilなど、メソッドを実行する前提条件を事前にチェックしています。

初見ではやたらリターンしていて、特別な記法か何かかと混乱しましたが、 前半に続くreturn文は前提条件のチェックをしていると覚えておけば良さそうです。

早期リターン - Google 検索

三項演算子

score= 50
result = score > 40 ? 'Pass' : 'Fail'
puts result

突然のifは後置ifでしたが、突然の?は三項演算子です。

<条件式> ? <真式> : <偽式>

となっていて、条件が正だったら:の前が実行されて、 負だったら:の後ろが実行されます。

上の例だとscore > 40は正なので、 resultは:の前の'Pass'になります。

突然の?で混乱したら三項演算子で調べると解決するはずです!

三項演算子 - Google 検索

null(nil)チェックって本当に必要?

一人で小さいプログラム組んでいる程度だと、nullになることはほぼありませんでした。

でもWebの世界ではnullチェックは基礎のキで当然やるものみたいな文脈で語られていたので、 腹落ちしてなくてもやもやしてたのですが、実際のWebサービスを触ってようやく腹落ちしました。

たとえば、Googleのスプレッドシートもそうだと思うのですが、 同じ画面にログインユーザー、ゲストユーザーなど色々な権限のユーザーがアクセスする可能性があります。

ログインユーザーならユーザー名登録しているけど、ゲストユーザーはしていない。 そんな状況で、画面にユーザー名表示すると、ログインユーザーは表示できるけど、 ゲストユーザーは登録してないのでnullになる。

もしnullならチェックしてGuestって名前で表示するようにしてあげれば、どっちでも対応できるようになる。

こう考えるとnullチェックって確かに必要だなと納得できました。 実際直面しないと分かり辛いですが、事前にイメージを膨らませておくと捗ったと思います。

参考になりそうな記事:

その「Nullチェック」必要ですか? ~レビューで指摘を一つ減らすために~ - Qiita

でも、とにかくnullチェックしてれば良いというわけでもないみたい

もういい加減「nullチェックをしたら安全」とかわけのわからないことを言うのはやめよう - Qiita

Pushする勇気!

チームで開発を始めて、頻繁にGitを使ってPushしたり、Margeするようになりました。

それまでは一人で書いて一人で更新するだけだし、間違ってPushしても何も問題なかったのですが、 みんなで参照しているブランチを更新するようになりました。 間違うと色々と迷惑をかけそうでびくびくしながらPushやMargeをしていました。

そしてやはりというか、マージした後に、バグがあって修正が必要になりました。 駆け出しには軽くパニクるシチュエーションだったのですが、 「Revertすればいいですよ」って何も問題がないように教えて貰い、 あっという間にバグのある前のバージョンに戻すことができました。

いや、当たり前じゃんと思う人も多いと思いますが、 いままでGitの機能でバージョンを戻すとか考えたことがなかったので;;;

作業ミスがないようにするのが一番というのは一旦置いておいて、 何よりいざという時に、取り返しがつくというのは知っているだけで、心理的にとても安全になります。

もしも間違ってPushしたり、Mergeした時はどうすればいいですか?っとあらかじめ聞いておけばよかったなと思います。

開発はSlackの上で廻っている

職場によると思いますが、 テスト結果もエラーもコミュニケーションもなんでもSlackに通知を集約していて、 こんなにSlack上で業務が完結しているとは思いませんでした。(便利です) Slackと連携できないツールは使わないという人がいるのも納得です。

Ruby On Railsでのつまずき

メタプログラミング 存在しないメソッドが使われている?

メソッドが何をしているか調べたい時は、メソッド名でgrep検索してたのですが、 ある時どこを検索しても、メソッドが見つからず狐につままれた感じになりました。

なんだかメタプログラミングという手法があって、 メソッドを動的に生成することができると知りました。

たとえば下記のように書くと、define_methodメソッドの引数に渡している名前でメソッドが作成されるため、 Greetingクラスでcatとdogというメソッドが使えるようになります。

メソッドの定義は必ずdefから始まると思い込んでいたので、以下の例だと、def dog から始まる箇所を探していたのですが、 define_methodで動的に生成されているので、いくら調べてもメソッドの定義を見つけられませんでした。

class Greeting
  { :cat => 'Meow', :dog => 'Bowwow' }.each do |name, message|
    define_method(name) { message }
  end
end
 

define_method (Module) - Rubyリファレンス

メソッド検索しても出てこないのは、エディターがおかしいのではなく、 メタプログラミングという手法ががあることを知っておきたかったです。

メタプログラミング ruby - Google 検索

tryとmap 教本は教えてくれなかった現場でよく使うメソッド

tryとmapは教本ではほぼ使われてなかったけど、ここ2ヶ月でやたらと目にするようになりました。

雑説明ですが、tryはメソッドの呼び出し時のnilチェックをよしなにやってくれるメソッドで、 mapは配列を便利に扱えるメソッドです。

try

tryを使用しない場合、通常通りnilチェックをする必要があります。 例えば以下ではユーザーがnilではないかチェックして、 nilではない場合のみ@user.nameを実行しています。

unless @user.nil?
  @user.name
end

もしも@userがnilの状態でnameを実行すると、 NoMethodError: undefined method `name' for nil:NilClass というエラーが発生してしまいます。

tryメソッドを使用した場合は、@userがnilの場合はエラーではなく、nilを返すようになるので、 中身がnilかどうかを確かめてからメソッドを呼び出すコードが簡潔にかけるようになります。

追記

nilチェック = tryと書きましたが、厳密にはnilチェック = &. でした;; 両方のメソッドでnilをチェックする挙動は同じですが、 tryはnilチェックに合わせて、*メソッドが呼び出し可能かどうかまで確認していました。 なので、tryだと

unless @user.nil?
  @user.name
end

とはイコールの挙動になっていません。

以下のように@userがnameメソッドを呼び出す際に、 @user.try(:name)ではメソッドが存在していない場合もnilを返すのに対して、 @user&.nameではエラーを返しています。

 pry(main)> @user.try(:name)
=> nil
 pry(main)> @user&.name
=> nil
 pry(main)> @user = "isobe"
=> "isobe"
 pry(main)> @user.try(:name)
=> nil
 pry(main)> @user&.name
NoMethodError: undefined method `name' for "isobe":String

Railsのtryメソッドのソースを確認すると、 以下のように引数で渡したmethod_nameがnilかどうか確認する以外にも、 respond_to?(method_name)の部分でメソッドが呼び出せるかどうかも確認しています。

def try(method_name = nil, *args, &b)
  if method_name.nil? && block_given?
    if b.arity == 0
      instance_eval(&b)
    else
      yield self
    end
  elsif respond_to?(method_name)
    public_send(method_name, *args, &b)
  end
end

github.com

map

配列を処理する際に、初心者向けの教本ではeachを使うことが多いと思います。 例えば、1から3の数字に1を足した結果が欲しい時、eachで処理した場合の返り値は処理対象のもともとの配列なので [1, 2, 3]になります。 そのため、処理結果を取得したい場合には、eachブロック外で変数を定義して、ブロック内で結果を保存する一手間が必要です。

result = [] 
[1, 2, 3].each do |i|
 result <<  i + 1
end 

一方でmapで処理した場合は、処理を実行した結果の配列が返り値になるため、 返り値をそのまま使用することができます。

[1, 2, 3].map do |i|
  i + 1
end  

blank? nil? present? exist? Nilチェックするのも一苦労

nilチェックするにも使えそうなメソッド探すとnil? empty? blank? present? とか色々あってどれ使うのが正解か分かりませんでした。

今はblank? present?使うのが良いと思ってるのですが、 これも使用頻度が多いので事前に詳しく調べておけばよかったです。

参考になりそうな記事: nil? empty? blank? present? の使い分け - Qiita

継承 またまたメソッドが存在しないです

クラス内で定義されていないメソッドが、そのクラスで突然呼ばれていて、 検索すると、そのクラス以外のファイルに定義されいました。

継承すると外部の機能をクラスに取り込むことができるようなのですが、 駆け出しからすると、突然実行できるはずのないメソッドが実行されたように見え混乱するポイントでした。

継承の概念は知っていたのですが、 いざ直面するとフリーズするのできちんと理解しておきたかったです。

ruby on rails 継承 - Google 検索

Nプラス1 パフォーマンスも大事

Ruby On RailsはSQLを書かなくても、ActiveRecordがいい感じにクエリを作ってくれますが、 気をつけないと無駄なクエリが大量に発行されて、パフォーマンス落ちてしまうらしいです。

今までパフォーマンス気にしたことがなかったのですが、 周りの先輩方が注視しているのと、Nプラス1なところをリファクタリングすると、 表示スピードが結構変わるのを見て、大切なんだなと学びました。

Active Record クエリインターフェイス | Rails ガイド

Eager Loading 熱心なローディング?

直訳すると熱心なローディングで名前から挙動が想像しづらいですが、 これもDB関連で、これから必要になるであろうテーブルのデータを事前に読み込んで、 キャッシュしてくれるみたいです。

キャッシュする挙動のイメージがつきづらく理解に時間がかかりました。 Nプラス1を防ぐためにも使われているようで、 随所出てくるので、事前に学んでおきたかったポイントです。 Active Record クエリインターフェイス | Rails ガイド

最後に

まだまだ色々ありますが、2ヶ月間、想像できなかった概念やつまずきがたくさんありました! 駆け出しから中堅になるくらいまでのノウハウって、素人から駆け出しになる時より、圧倒的に情報が少ない気がするので、 また機をみて書けたらいいなと思います!