RET

Reflection English Technology

オンラインイベント「顧客提供価値を高めるための技術的負債への向き合い方」感想・学び

先日こちらのオンラインイベントに参加させていただきました。色々なことを学ばせていただき、とても良いイベントでした。印象に残ったお話や感想を軽くまとめていこうと思います。

顧客提供価値を高めるための技術的負債への向き合い方 (2022/11/10 12:00〜)

技術的負債の解消に積極的な人が少ないので、メンタル的にハード

以前、参加させていただいた「良いコード/悪いコードで学ぶ設計入門」の著者トークで著者の仙塲さんも似た体験をされたとお話しされていました。やはり、レガシー改善に対して消極的な人は一定数いるんだなと再認識しました。

技術的負債の解消をスタートさせても、「それいいね!どんどんやっていこう!」て感じで仲間が増えていくところまでいくのが大変だそうです。

技術的負債の解消に積極的でない人たちと敵対関係を作らないような配慮も重要です。

技術選定の観点

  • 今いるメンバーの技術スタック的にマイグレーションしやすいか
  • 採用で魅力的に映るか

等の視点で新しい技術を選定していったというお話もありました。

技術選定はシンプルに技術の特性を理解しているだけでなくて、メンバーのことやビジネスのことも考慮する必要があるんですね。

ビジネスの成長とレガシー改善の足並みを揃えるのが難しい

ビジネス側の人たちにとっては事業の成長が最優先事項であり、技術的負債の解消にあまり関心がないケースがあるみたいです。そのため「技術的負債を解消させてください」とビジネスサイドを説得するのが難しく、「生産性を上げるために〇〇したい」みたいな宣言をしてしまうと、どのくらい改善したかという数字を出す必要が出てきてきついというお話がありました。こういった事情があるため、技術的負債の解消はビジネス成長のための機能追加と同時にしれっと実行しているそうです。

「許可を得ないとやれないというマインドでやっているといつまでもやれない」というのはとてもリアルな経験談でためになりました。

メンバーや経営陣に対する働きかけ

  • 経営者に対して、リプレイスへの投資の意義や費用対効果に関する説明責任がある
  • 開発メンバーがどんどん挑戦していけるような文化を醸成する

技術的負債の解消に着手する前段階の環境作りって予想以上に根気が必要そうです。

また、リーダーシップと同じくらいフォロワーシップも大事というお話があり、その通りだなあと思いました。

挑戦を後押しするような雰囲気を作るには、リーダーだけが頑張ればいいのではなく、その他の開発メンバー一人一人の協力がとても大事であるということです。たとえリーダー的ポジションでなくても、開発メンバー個々人が「チームの変革者」として当事者意識を持つことがチーム全体を良くしていくのかもしれません。

感想

技術的負債の解消って、いわゆるレガシーコードをどのように改善していくかみたいなところがメインだと思っていました。しかし、今回お話を聞いて、コードをどういじるかよりも、コードの外にある色々な要因の調整がとても重要であることを学べました。私自身もフォロワーシップ、リーダーシップを発揮して技術的負債を解消していけるようなチーム作りに貢献したいと思います。

FactoryBotで、特定の属性の値が異なる大量のテストデータを作りたい時のメモ

FactoryBotで大量のテストデータを作りたい時にはcreate_listメソッドが使える

create_list(:food, 100)

これでFoodのレコードが100件保存される。

では、消費期限が異なるFoodのレコードを100件作りたい場合はどうするか。

以下のようにcreate_listメソッドにはブロックが渡せる。

create_list(:food, 100) do |food, i|
  food.expiration_date = Date.today + i
end

これで、expiration_dateの値が異なるFoodのレコードを100件作れる。と思いきや、、、

expect(Food.all.pluck(:expiration_date)).to eq []

=>
expected: []
     got: [nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil、、、(省略)

レコードは作られるものの、expiration_dateが全てnilになってしまう。

create_listにブロックを渡したときの挙動

下の記事の表現を引用させていただく。

https://dev.to/hernamvel/the-optimal-way-to-create-a-set-of-records-with-factorybot-createlist-factorybot-buildlist-1j64

create_listメソッドは以下のような挙動になる

def create_list
  object = build the object
  object.save!
  yield(object) if block_given?
end

つまり、foodをsaveした後に、そのsaveしたfoodをブロックに渡すという挙動になる。

そのため、すでにsaveされたfoodに対してexpiration_dateをセットしているものの、再度saveされていない(expiration_dateを更新していない)ためexpiration_dateはnilのままになる

解決策

以下のようにブロックの中でsave!をする。

create_list(:food, 100) do |food, i|
  food.expiration_date = Date.today + i
  food.save!
end

しかし、上のやり方だと、ひとつのオブジェクト(food)に対して2回saveが走る。

以下のようにbuild_listを使うと1オブジェクト1saveでテストデータを作成できる。

build_list(:food, 100) do |food, i|
  food.expiration_date = Date.today + i
  food.save!
end

ただ、このやり方で100件もsaveするとSQLの発行回数も100件になってしまい、テストが非常に重くなる。

ということで以下のようにバルクインサートする。

foods = build_list(:food, 100) do |food, i|
  food.expiration_date = Date.today + i
end

Food.insert_all foods.map(&:attributes)

参考文献

<Rails>sessionメソッドの実装について軽くコードリーディングしてみた

はじめに

session "メソッド" って言うけど、使われ方が全然メソッドっぽくない。

sessionメソッドは以下のようにして使われる。

session[:user_name] = user.name

まるでハッシュのようだ。

しかも

session.class
=> ActionDispatch::Request::Session

というふうにあたかもsessionというオブジェクトに対してclassメソッドが使えているように見える。

とはいえ、RailsチュートリアルRailsガイドにもsession (インスタンス)メソッドと書いてあるので当然ながらメソッドである。

コントローラー内でbyebug↓

(byebug) defined? session
#=> "method"

続けてsessionとだけ打ってみる。

(byebug) session
#<ActionDispatch::Request::Session:0x00007ff84f3fc9c0 @by=#<ActionDispatch::Session::CookieStore:0x00007ff853201cc0 (長いので省略)>

sessionメソッドでActionDispatch::Request::Sessionのインスタンスが返る。

つまり、session[:user_name] というのはsessionメソッドの戻り値であるActionDispatch::Request::Sessionのインスタンスに対して[]= メソッドが呼び出せているということになる。

sessionにclassメソッドが使えているのは、sessionメソッドの戻り値であるActionDispatch::Request::Sessionのインスタンスに対してclassメソッドが呼び出せているという仕組み。

ということは、[]= メソッドがActionDispatch::Request::Session内に定義されているはずなのだが、ActionDispatch::Request::Sessionに行き着くまでにコードがどのような流れで処理されているのかをコードリーディングしたい。

コードリーディングして実装を調べてみる

trace_locationを使用してsession[:current_user_id] = 7というコードがどのような流れで処理されていくのかを調べてみる。

https://github.com/yhirano55/trace_location

TraceLocation.trace do
   session[:current_user_id] = 7
end

そうするとログが得られるので、内容を以下で要約。

処理の順番
1. ActionController::Metal#session2. Rack::Request::Helpers#session3. Rack::Request::Env#fetch_header4. ActionDispatch::Request::Session#[]=**

順番に見ていく。

ActionController::Metal#session

sessionメソッドが使われると、まずここに処理が飛ぶ。

delegate :session, to: "@_request"

https://github.com/rails/rails/blob/main/actionpack/lib/action_controller/metal.rb#L157

delegateメソッド

delegateは以下のメソッドを自クラスに定義しているのと同じ。

def session
  @_request.session
end

つまりActionController::Metal内でsessionインスタンスメソッドが定義されてる。

ApplicationControllerがこのActionController::Metalを継承しているため、UsersController等の自作のコントローラー内でもsessionインスタンスメソッドが使用できるというわけだ。

@_requestは何者か?

@_requestはおそらく、ActionDispatch::Requestのインスタンスである。

なぜなら、sessionメソッドの実体は以下で見ていくRack::Request::Helpersに定義されているのだが、このモジュールをincludeしているのがActionDispatch::Requestしかないからだ。

https://github.com/rails/rails/blob/6291a9f6d36d77b32df7d07a8c7c56103a555d39/actionpack/lib/action_dispatch/http/request.rb#L19

Rack::Request::Helpers#session

def session
  fetch_header(RACK_SESSION) do |k|
    set_header RACK_SESSION, default_session
  end
end

@_request.sessionを実行するにあたり、次はsessionメソッドの実体を探しに行く。

(trace_locationを知るまでこのコードに辿り着けなくて苦労した、、)

fetch_headerってなんやんということで次。

Rack::Request::Env#fetch_header

def fetch_header(name, &block)
  @env.fetch(name, &block)
end

@envとは何かがわからなかったので以下を参考にする。

https://qiita.com/coe401_/items/ad7dc2f3e319c5beaf40#%E3%83%AC%E3%82%B7%E3%83%BC%E3%83%90env%E3%81%A8%E3%81%AF

@envはHTTPヘッダを表すハッシュ

nameRACK_SESSION

&blockset_header RACK_SESSION, default_session (厳密に言うとdo ~ endのかたまり)

fetchメソッド

Hash#[]と同じく、指定したkeyのvalueを取得する。

Hash#[]と違いkeyが無い場合nilではなく例外が発生する。

第二引数にデフォルト値を指定することが可能。key が存在しない場合はこのデフォルト値が返る。

book = { name: 'hoge', price: 1000 }
book.fetch(:name, "fooo")
=> 'hoge'

book.fetch(:author, "foobar")
=> 'foobar'

つまり@envというハッシュからname(つまりRACK_SESSION)というkeyを探し、存在しなければ&blockが返る。

trace_locationのログにset_headerに関するものがないため、(僕の環境で)sessionメソッドが走った時はRACK_SESSIONというkeyが存在していたということなのだろう。

ActionDispatch::Request::Session#[]=

def []=(key, value)
  load_for_write!
  @delegate[key.to_s] = value
end

ここで[]=メソッドの定義に処理がとぶ。

つまりはここまででsessionメソッドの処理が終わったということである。 sessionメソッドの戻り値はActionDispatch::Request::Sessionのインスタンスなので、RACK_SESSIONというkeyのvalueがActionDispatch::Request::Sessionのインスタンスであると推測できる。

@delegate

@delegateとはなんだろうか?処理を止めて調べてみる。

(byebug) @delegate
{"session_id"=>"f15808a61b80a6b1f8143482897524a2", "_csrf_token"=>"tqNAbzcy135NjTirnmZbtIjHcS9mAXQMWhku37T9iuk=", "current_user_id"=>7}

https://github.com/rails/rails/blob/7c1165c8c8752a84a9d02ef06fccbf113b8ff6b0/actionpack/lib/action_dispatch/request/session.rb#L69

@delegateにはsessionの中身が入っていた。

つまりは

session[:key] = value

でsessionにデータを追加したり更新できたりするということになる。

load_for_write!に関するログもあるが、お腹いっぱいのためここまで。

説明力を磨くためにはどうしたら良いか ー原因と対策ー

はじめに

まず今回ターゲットとしている「説明」とは

  • 相手に話を理解して欲しい
  • 相手を納得させたい

以上2つを目的としているものである。

「議論で勝ちたい」、「セールス等で相手に何かしらの行動をとってほしい」といったケースのテクニックに関しては一部共通するものの、基本的には取扱の対象外とする。

なぜ説明が下手なのか

頭がいい = 説明が上手ではない

頭がいいはずの大学教授や専門家は全員説明が上手かと言われるとそうではない。つまりは頭の良さと、説明力は必ずしも結びつかない。

とはいえ、できるビジネスマンは総じて説明がうまい。

説明力はある種テクニックなので(= 先天的な問題ではない)、練習していくことで必ず上達していく。

相手の理解度や、相手が聞きたいことを考えていない

相手を無視した説明はうまくいかない。

たとえ緊張する場面でも、「相手がどういう目的で話を聞いているか」を意識することで、自ずと話す順番やどのような話し方をすればいいかがわかってくる。

また、「相手の理解度を考えない説明」も問題である。例え結論ファーストで説明しても、前提となる知識がない場合わかりづらい説明にある可能性がある。

考えた順番で話す

自分の頭に浮かんできたことをそのままの順番で口に出すと、結局わかりにくい説明になる。

自分が考えた順番ではなく、相手が聞きたい順番で話すことが非常に大切。

そうすることで理解しやすい説明ができる。

自分でもよくわかっていないことを説明しようとしている

頭に浮かんだ順番で口に出してしまう。これは説明している内容が自分でもよく理解できていなかったり、内容を自分の頭の中を整理できていないからだ。

説明をうまくするには相手に何を伝えるべきかをあらかじめ明確に理解している必要がある。

また、突然意見を求められるシーンでは事前に伝えたいことを整理できないことがある。そういった時は仮説思考を使ってみるといい(後述)。

説明の技術を勉強しても、全く実践しない

インプットは非常に大事であるが、実践を繰り返してく中で説明力は身に付く。必ずインプットした内容を、実際の説明の場でアウトプットする必要がある。

説明の順序について

基本はピラミッド

ピラミッド(CRF法)

結論、根拠、具体例

説明における基本の型。 大ベストセラー「1分で話せ」では、この三層構造を「ピラミッド」と表現し、ただひたすらに、結論ファーストの順序で話すよう書かれている。 自分が話すときだけでなく、話を聞くときもこのピラミッドを意識するといいらしい。

前提 → ピラミッド

前提、結論、根拠、具体例

「1分で話せ」以外の本では、結論ファーストの説明だけだとわかりずらくなるシーンがあることが言及されている。

なぜ、学校の先生の説明はわかりずらかったのか。それは我々生徒の理解度を考えていなかったり、話を理解する上で前提となる情報が足りていないからだ。

このような状態で結論ファーストで話しても、その説明は理解しにくい。

ちなみに自分が言葉にしていない部分を相手は頭の中でそれとなく補っており、それを補うために使っている知識や考え方を「共通の基盤(by Clark, 1996)」というらしい。

結論ファーストで話す前に、この共通の基盤を作る必要がある。

ピラミッド → 結論(PREP法)

結論、根拠、具体例、結論

  • 最初の結論は最後の結論と同じ内容にする
  • 根拠は客観的に判断可能な理由を提示する
  • 前に述べた根拠を、よりイメージしやすくするような例を挙げる
  • 情報量が多くならないように端的にまとめる

ピラミッド以外のパターン

SDS法

概要(summary) 詳細(Details) 概要(Summary)

  • 最初の概要は相手に覚えてもらいたいことを1つ決めて、それを絶対に覚えてもらいたいということがわかる言い回しで伝える
  • 詳細では、最初の概要の解像度を上げる
  • 最後の概要では、情報量が多くなりすぎると相手に内容を覚えてもらいにくくなるので、端的にまとめ上げるのが大事
  • 相手に伝えたい情報の中で、序盤と終盤に伝えた情報が中盤に伝えた情報よりも記憶に残りやすくなる。これは認知心理学において「初頭効果」と「親近効果」と呼ばれている

  • 具体例

    • 現在、ログイン画面の修正対応を進めています
    • 具体的には、文字入力のサジェストがうまく機能しておらず、原因を特定中です
    • 今日中に原因を特定して、コードの修正に取り掛かろうと思います

(結論 → 詳細 → まとめ といった流れだがSDS法はこんな感じでいいみたい)

TAPS法

理想の姿(To be), 問題を抱えた現状(As is), 問題(Problem), 解決策(Solution)

相手に何かしらの提案をしたいときに使える型

  • 最初に相手のあるべき理想の姿を確認する
  • 問題を抱えた現状を指摘する
    • 相手にとって耳の痛い情報なため、できるだけコンパクトに指摘する
  • 問題を指摘する
    • 理想と現状のギャップを埋めるために解消すべき問題を指摘する
  • 解決策を提示する

いろんな型に共通するエッセンス

話していくにつれて、話の解像度をあげていく

話の解像度を徐々に上げていくことで、相手の「聞きたい!!」「もっと知りたい!!」という興味を引き立てることができる。

  • 「全体像→具体説明」もしくは「抽象 → 具体」の順序

全体像や話の大枠を示す。

具体的な説明をする。

この順序で話すことで認知科学的に理解が促進される。

  • 「知らない→知っている」の順序

先にあえて相手が知らなそうなことを話す。その後徐々に詳しく説明していく

ex) 「用語解説」の型

相手がある用語を知っているか最初に確認する

その用語の定義を一言で伝える

用語そのものの意義やメリットを伝える

具体例を出す

  • 「難しそう→簡単そう」の順序

先にあえて相手にとって理解が難しそうなことを話す。その後徐々に詳しく説明していく。

ex) 「咀嚼」の型

相手にとって理解するのが難しそうな情報を先に提示する

噛み砕いた言い回しで伝える

ex) 「分類」の型

先に相手に理解してもらいたい対象を列挙する(この時点だと相手はよく理解できない)

分類するグループ数とそのグループ名を示す

最初に列挙した対象を各グループに割り振る

聞いている相手の様子を適宜伺う

どんなに有効な型を知っていて、それを実践していても聞いている相手の状況を無視していたら効果がない。

例え十分な説明をしたとしても相手にそれが伝わっていなそうなら、適切なタイミングで説明を区切って相手の理解度を確かめる。

説明力向上のために今日から行えるアクション

型なんて覚えられない!という人が多いと思う。ただ、このままだといつまでたっても自分の考えた順番で口に出していく説明から脱却できない。

本気で説明力をあげたいと思っている人が、実践すべきアクションが以下である。

「出す」→「選ぶ」→「並べる」

泥臭いやり方であるが、非常にシンプルで実践しやすい。

「出す」

説明に必要な要素を箇条書きで書き出していく。こうすることで頭の中のものを全て可視化することができる。

相手に理解してもらうためにはどのような要素が必要か、思いつくものを書き出してみる

「選ぶ」

箇条書きで書き出したものから必要なものだけを選び取る。

選び取るためのコツはターゲット思考、つまり話し相手がどういう人間か、何を欲しているのかを考えること。

(ちなみに本によっては「選ぶ」ではなく「捨てる」というふうにして言及しているものもある)

「並べる」

選び取ったものを相手に伝わりやすいように並べる。

ここで「話す順序の型」がとても役に立つ。型を意識しながら選び出した要素を適切な順序に並べる。

こうしてまとまった内容を相手に対して説明していく。

仮説思考

何かを説明するということは一方的な活動ではない。

相手の思考を整理しながら、少しずつ相手の理解に近づけていくこともとても大事。

そこで重要となるのが仮説思考。

仮説思考とは、「正解」がわからない、もしくは「正解」への情報が少ない状況の中で、問題の全体像や結論を考えて仮説を作る思考法である。

例えば休日に友人と遊ぶ予定があるものの、何するかまだ決まっていないという状況があったとする。

その状況下で「何を選ぶか」「それはなぜか」を考える。このときに友人が何で遊びたいかという情報は参考程度に留めておいて、現状を分析してみる。

  • 天気予報では猛暑日予想なので、涼しいところで遊ぶのがいいかもしれない
  • コロナにかかりたくないので、人混みが少ないところや屋外で遊ぶのがいいかもしれない
  • 最近車を買ったので、遠くに行ってもいいかもしれない

このように考えた結果「軽井沢にドライブに行く」というアイデアを思いついたとする(人混みが少し多そうだが、、)。

そこで友人に軽井沢にドライブ行くのはどうだろうかと質問した結果、「遠すぎるからやだ」というレスポンスが返ってきた。つまり最初の仮説は間違えていたということになる。

その後「じゃあ秩父にドライブするのはどうだろうか、軽井沢よりは近いよ」と提案してみる。

このように一つの仮説を立てて、会話の中で方向修正を繰り返して正解を探していくのが仮説思考のやり方である。

大事なことは

  • 最初から正解を当てにいかない。少しずつ正解に近づけようという心構えで仮説を立てる
  • 考え抜いた仮説である必要がある

最後に

説明のためのテクニックについて色々と調べてみたが、ワーキングメモリや睡眠といった基礎となる脳の機能も重要かもしれないので、今度調べてみようかと思う

参考

www.amazon.co.jp

www.amazon.co.jp

www.amazon.co.jp

www.amazon.co.jp

www.amazon.co.jp

www.amazon.co.jp

www.amazon.co.jp

エンジニア1年目で学んだことを振り返る

はじめに

未経験からエンジニアになってはや一年、、、 あっという間の一年間でした。 今後もより一層開発に貢献していくために、これまでの学びを振り返ろうと思います。

要件をしっかりとヒアリングする。要件が不明瞭な状態で開発を進めない

ビジネスサイドの方たちの要望をシステムに落とし込んでいくことが僕の仕事です。

以前、複雑な機能実装を任された際に、テキストで書かれている機能要件を自分の解釈で汲み取って開発を進めてしまったことがありました。その結果、ビジネスサイドの方が実現したかった機能とは少し食い違ったものが完成してしまったことがあります。

このような開発の後戻りを防ぐためにも「対話」が非常に重要です。

また、実装が難しいわりに、ビジネスとして効果が薄い要望もあります。そういった要望をもらったときに、開発者側とビジネスサイドで適切な落とし所を見つける必要があるということも教えていただきました。

対話をしていく中で、相手が本当に実現したいことは何かをしっかりと見極めていくことが大事であると学びました。

前提を疑う

「今自分はこのコードをコントローラの中に書こうとしているけど、そもそもそれは正解なのか?」

「マーケターさんはこう言っていたけど、本当に実現したいことはこれであっているのか?」

このように「○○という前提で進めようとしてるけど、本当に正しいのか?」とクリティカルシンキングを働かせることも重要だと思いました。

極力、拡張性のないレガシーコードをベースに新しい機能を追加しない

僕が開発しているサービスは過去に一度リニューアルが行われたのですが、その時の担当者が現在誰もいません。

そのため、どのような意図で書かれているのか等が現在の開発者全員よくわかっていないというコードが存在しています。

そのようなコードをベースに、ビジネス的に重要な機能を実装することがありました。僕は拡張性、保守性のあるようなコードを書くためにかなり時間をかけて実装を進めました。

ところが、最終的に出来上がったコードをレビューしてもらったときに、「1度ゼロベースで設計し直したほうがいいかもしれない」と提案されてしまいました。

一生懸命書いたコードが、結局拡張性を欠いたものになってしまい、とても悔しかったです。

この経験から、設計としてあまりよろしくない既存のコードをベースに、機能を追加をすることは極力避けるべきであると学びました。

ただ、一見よくない設計に見えても実はそう設計せざるを得ない事情があったり、タスクの納期的に一から設計している時間がないといったケースも考えられるので、ある程度の妥協が必要かもしれません。

既存のコードを書いたエンジニアに設計の意図を聞いたり、事業側と納期に関する相談をしたりと、いいコーディング(設計)をしていくための「対話」が重要になってくると思います。

責務を意識しながらコードを書く

コードレビューの中で、「ここのmodelの責務を考慮すると、このメソッドはこのmodelにおくべきでない」だとか「凝集度が低いクラスになるから、責務を分離した方がいい」といったレビューをもらうことがあります。

この辺りの責務を意識したコーディングは「良いコード/悪いコードで学ぶ設計入門」や「リーダブルコード」などでも勉強していましたが、適切に実践できていませんでした。

また、良いコードを書くにはどうしたいいか学ぶ中で、以下のような動画をyoutubeで見つけました。

https://www.youtube.com/watch?v=hX9kCwdR8dc

個人的にとても腑に落ちました。

オブジェクト指向」だとか「デザインパターン」だとか「クリーンアーキテクチャ」だとか色々なコーディング(設計)の技法がありますが、とりあえずまずはシンプルに責務を意識することでgood enoughなコードが書けている気がしています。

目の前の仕事を全力でやることで力がつく

僕は、子供がいて業務外で学習時間が思うように取れない事に悩むことがありました。実力的にもっと勉強しないといけないし、そもそも勉強が好きなので勉強の時間があまり取れないのが割と苦痛でした。

twitterを見ると業務外でたくさん勉強している駆け出しエンジニアをよく見かけます。そのような人たちと自分を比較してしまい、嫌な思いをすることもありました。

そんな時に以下のブログ記事に出会いました。

https://soudai.hatenablog.com/entry/2021/12/23/111510

https://soudai.hatenablog.com/entry/2021/12/31/114009

私はまだ経験が浅いので、業務外でどんどん勉強していく必要があるのは間違いありません。

また、仕事を全力でやるだけで強強エンジニアに追いつけるなんてことも全く思っていません。

ただ、この記事を読んだ後、確実に仕事に取り組む姿勢が変わっていったと思います。具体的には、(設計をよく学べるらしいので)時間がある時にリファクタリングをやらせてくださいと申し出たり、TDDを勉強して仕事で実践してみたりと、仕事の中で主体的に学びを得ようと心がけるようになりました。

これらの記事を読む前までは、淡々と与えられたタスクを期限までにこなすことしか頭にありませんでした。

しかし、自分次第でその一つ一つのタスクの中で色んなことを学ぶことができる事に気づくことができたと思います。

ドキュメンテーション力がとても大事

エンジニアにとってドキュメンテーション力(知識、知見をわかりやすく文章化する技術)はとても大事だなと思う時がありました。

具体的には

  • 個人的に手本にしているエンジニアが書いた新機能の仕様書がすごかった
  • 自分が退職していなくなった後に他の人が読んで意図が伝わるようなドキュメントを書く必要があると先輩エンジニアに教わった

ドキュメンテーション力をあげるためにも、技術記事等のアウトプットは不可欠だなと実感しました。

タスクを細分化する

たまに、何から手をつけていくかわからなかったり、なぜかやる気の出ないタスクに遭遇することがありました。(後者は達人プログラマーでいうところの「爬虫類脳」からの危険信号なのだと思います)

そういった時に打開策はないかと色々調べて見つけたのが、タスクの細分化です。 特に以下の記事はとても勉強になりました。

https://qiita.com/jnchito/items/017487cd882091494298

タスクを細分化するという技を覚えて以来、自分のNotionにタスク管理のカンバンを作って、やるべきことを見える化して整理するようになりました。

保守性、可読性を担保しつつスピーディな開発をしていく必要がある

「良いコード」を書いていこうとすると、逆にスピードが落ちてしまうことに悩むことがありました。そんな時に先輩エンジニアとの1on1で教えてもらったのが「QCD」という概念でした。 QCDはもの作りに重要な3つの要素であるQuality(品質)、Cost(コスト)、Delivery(納期)の頭文字をとったものです。特に品質が重要とされ、この3つはトレードオフの関係にあるとされています。 1on1の中ではこのバランスを経験で知っていくのがいいね〜という話でまとまり、非常に納得感がありました。

また、以下の素晴らしいスライドを発見しました。

https://speakerdeck.com/twada/quality-and-speed-2022-spring-edition

短期的にも長期的にも、崩壊したコードを書くほうが、クリーンなコードを書くよりも常に遅い

コード品質を高く保っていた「にも関わらず」速いのではない。コード品質を高く保っていた「からこそ」速いのだ

質とスピードはトレードオフでないことが力説されており、目から鱗の連続でした。

シンプルに技術力を上げていく(保守性の高いコードを書けるようになる)だけでなく、「ソフトウェア開発の最初から最後まで関わる経験」もしてみたいと思うようになりました。

最後に

web開発は楽しい、というのが1年間やってみてのざっくりとした感想です。 自分が作った機能をユーザーに使ってもらえることにとてもやりがいを感じました。 そして無限増殖する「学ばないといけないこと」にキャッチアップしていくプロセスを充実感を持って楽しめている気がしています。

2年目以降も楽しいという気持ちを忘れずに、いろんなことに挑戦して行けたらなと思います。