筆者について
- 筆者は地方中小SIerの現職エンジニアです。3年目で実力はまだまだですが、主に初学者・未経験者・独学者へ向けた記事を作成しています。
-
筆者はスキルアップ&Web系企業への転職を目指し、HappinessChainというスクールで勉強を進めております。- →Web系企業への転職が決まりました。
- 若干の開発経験者として、最近はスクール内の初学者の方にペアプロを行うことが増えてきました。ペアプロの中で、初学者の方はプログラミングの進め方そのものを知る機会がほとんどない ことに気が付きました。そういった初学者の方に「実装の方向性だけでも示したい」思いから本記事作成に至りました。
まえがき
- プログラム初学者、未経験の方にとってプログラムのコーディング作業はとても難しい作業だと思います。スクールに入っている場合、実装課題・コーディング課題になった瞬間太刀打ちできないケースも多いと思います。(筆者もかつてはそうでした。)
- 本記事は、筆者が先輩エンジニアに教わった 「コーディングの進め方」と自身の経験から得られた知見をマージしてマニュアルとして書き起こした ものです。
- 本記事で紹介する内容により、プログラミングを挫折する人が少しでも減れば幸いです。
- また、自分の思考をコードに起こせるようになるとプログラミングの面白さを感じる瞬間も増えてくると思います。一方で、「プログラミング面白いかも?」と思えるようになるのは時間がかかるのも事実です。
- 「少しでも早くプログラミングの面白さに気づく方が増えれば良い」と思いがあったことも、本記事を作成した理由の一つです。
本記事で伝えたいこと
- コーディング時に頭が真っ白になった場合は、以下の手順で進めるべし。
- ①自分がやりたいことを分解して日本語として書き出す
- ②日本語の真下にコードを書く(コメントの訳としての処理が真下に書かれるイメージ)
- ③②のコードが①でやりたかったことを満たしているか、ログで確認する
- ①〜③を繰り返して順に実装を進める
- 言語化するのが結局一番難しい。
こんな方に向けた記事です
- プログラミング初学者の皆さん
- 以下に当てはまる皆さん
- 実装を進める上での進め方や方針を知りたい
- コーディングを進めている中で手が完全に止まってしまった
- ChatGPTやQiitaの内容のコピペでなく自分の力でプログラムを構築していきたい。また、その方法を知りたい。
補足:プログラム実装を円滑に進める3要素
- 作業内容を問わず、プログラミングを進める上で以下の3要素を意識することが重要と筆者は考えています。
- 分解する:「困難は分割せよ(分解せよ)」
- 書き出す:「分解した内容は日本語で書き出せ」
- 確認する:「分解した内容が正しく動作することをひとつひとつ確認せよ」
- 本記事の内容は、この3要素をコーティング作業にフォーカスして解釈したものです。
注意書き
- この方法では 「日本語をコメントとして書く」ことを多用 します。
- コメントを書くのは自分の頭の中を整理することが主目的です。筆者もすべての実装で以下を行うわけではないです。しかし、自分の力量を超える実装の場合は、下記の手法を実際にやります。
- この実装方法で使うコメントは「コードの解説としてのコメント」ではなく、 「コードを書くための補助としてのコメント」 です。上級エンジニアの方々はご意見あるかと思いますが、温かい目でご覧いただけると幸いです。
- ※コメントを書いて行くことに関しては実際は賛否両論があります。慣れてきたら不要なコメントは書かないほうが良いと思うのは筆者も同意見です。
- 「コードの上に存在するコメントの功罪について」も後ほど記事化する、あるいは良い記事があればリンクを載せようと思います。
- 実装を進める上で絶対の方法はありません。下記の方法について筆者は汎用性・再現性が高いと感じておりますが、あくまで一例です。
- この実装方法の問題点に気づいた方や初学者向けのオススメの実装方法がある方は是非コメントください。
- 以下でも言及しておりますが、言語化する作業は簡単に見えてとても難しい作業です。プログラミングのための言語化トレーニング方法についても、後ほど記事化できればと考えています。
- 「言語化トレーニング方法について」※記事作成中
プログラムの実装方法(コーディング編)
- 例としてRubyでの実装を記載していきますが、言語問わず行える方法です。
- Railsのようなフレームワークでの実装の場合、考慮する要素がコーディングだけではありません。Railsでの実装の場合は、「実装の進め方(プログラム実装の全体方針編)」を後ほど作成する予定です。
- 「実装の進め方(プログラム実装の全体方針編)」 ※記事作成中
- Railsでのアプリ実装を進める中でコーディングする必要性が必ず出てくるので、いざコードを書こうとして頭真っ白になったら本章の内容をやりましょう。
手順
- ①自分がやりたいことを分解して日本語として書き出す
- ②日本語の真下にコードを書く(コメントの訳としての処理が真下に書かれるイメージ)
- ③②のコードが①でやりたかったことを満たしているか、ログで確認する
- ①〜③を繰り返して順に実装を進める
- ※③でうまく確認できない場合は①の分解の粒度が大きすぎることが多いです。
- ※実装順について、上側のコメントから順に実装する必要性はありません。 作りやすいコメントのコードから作っていきましょう。
ご存じの方が多いFizzBuzzを例に、実際の進め方をお見せしようと思います。
(FizzBuzzの実装内容が簡単すぎて、有用性が少し伝わりづらいかも…)
FizzBuzz問題
3の倍数のときは「Fizz」を出力
5の倍数のときは「Buzz」を出力
3の倍数かつ5の倍数(15の倍数)のときは「FizzBuzz」を出力
それ以外の場合は数字そのものを出力
①自分がやりたいことを分解して日本語として書き出す
- 自分がやりたいこと、どうやれば対象の機能が完成しそうかをコメントとして書き出していきます。仕様が与えられているなら、それを分解して書き出す、とも言いかえられます。
- ちなみにプログラミングっぽい単語でいうとこれは 「設計作業」そのもの です。
- 書き出す先は、コードのコメントとして書きます。
- どれくらいの粒度で書き出すか?は以下を参考にしてください。
- 「自分が書けるコード」の粒度感で書きます。
- 「自分が書けるコード」が不明な場合、細かすぎるなと思うくらいまで細かく日本語を書いてください。(実際にやってみるとわかると思いますが、最初のうちはこの作業は相当難しいです。)
- 最初のうちは、複数の処理を1つのコメントにまとめないように注意しましょう。「AAをしてBBをした後にCCをする」といった処理は、「AAをする」「BBをする」「CCをする」というように極力3つのコメントに分解しましょう。
- 複数の処理を1行のコードで行えるケースも実際は多いです。そのコードが「読める」「自力で書ける」のであれば、複数の処理を含んだコメントを書いても問題ありません。重要なのは「自分がコードが書けそうな日本語」まで分解することです。
- 変数名やクラス名、テーブル名等日本語に訳して違和感があるものは、英単語のままで問題ありません。 以下の「良いコメントの例」を参考にしてください。
- この際、極力プログラミングっぽい日本語を使ってコメントを書くよう意識しましょう。「変数」「取得する」「設定する」「定義する」「インスタンス化する」といったワードを使いこなせるようになると自然とコーディングが速くなります。
- 良いコメントの例
- 「変数hogeにvalueの内容を設定する」
- 「変数flagがtrueの場合、valueの内容を取得する」
- 「変数flagがfalseの場合、returnする(何もしない)」
- 「Carオブジェクトをインスタンス化し、変数carに代入する」(オブジェクト指向を想定)
- 良いコメントの例
- RailsのようなフレームワークでDB操作が関わる処理の場合、慣れないうちは操作するテーブルとCRUD操作 はコメントに書いたほうが良いでしょう。
- 良いコメントの例
- 「Usersテーブルにレコードを一つ作成する」
- 「変数
@post
のcomment項目を変数valueの内容で更新する」 - 「
@post
の更新に成功した場合、root_pathにリダイレクトする」 - 「
@post
の更新に失敗した場合、indexのビューをレンダリングする」
- 良いコメントの例
- FizzBuzzでやると以下のような感じです。この段階でコードは出てきません。
①FizzBuzzを日本語に分解
説明の便宜上各コメントに連番を振っておきます。
# a.数値を引数に取るFizzBuzz関数を定義する
# b.15の倍数の場合、FizzBuzzを返す
# c.3の倍数の場合、Fizzを返す
# d.5の倍数の場合、Buzzを返す
# e.それ以外の場合、数字をそのまま返す
# f.FizzBuzz関数を出力する
- オススメしない進め方
- 方針は考えるけどコメントとして書かない
- この実装方法でいちばん大事なのは 「書き出すこと」です。
- 頭の中で考えていることを文章化するのはめちゃくちゃ難しい作業です。必ず文章として書き起こしてください。(めんどくさいですけどね…)
- 日本語で説明できないコードを自力で生み出すことはできません。 言語化能力が向上すると、自ずとコーディング力も向上していきます。言語化能力のトレーニングになるので、書き出す作業まで行うことを強くオススメします。
- 方針は考えるけどコメントとして書かない
②日本語の真下にコードを書く(コメントの訳としての処理が真下に書かれるイメージ)
③②のコードが①でやりたかったことを満たしているか、ログで確認する
- ②と③はセットの作業です。以下をやっていきます。
- ①のステップが完了したら、書きやすいコメントからコードを書く
- コードを書く際には日本語の訳としてのコードを書いていくイメージです。「日本語→コード」へ翻訳していってください。
- コードがコメントとちゃんと対応しているか確認する。
- コードの動作確認はログに出力するような形が良いでしょう。
- ①のステップが完了したら、書きやすいコメントからコードを書く
- 「a.数値を引数に取るFizzBuzz関数を定義する」から実装してみます。
a.数値を引数に取るFizzBuzz関数を定義する
# a.数値を引数に取るFizzBuzz関数を定義する
def fizz_buzz(n)
end
# b.15の倍数の場合、FizzBuzzを返す
# c.3の倍数の場合、Fizzを返す
# d.5の倍数の場合、Buzzを返す
# e.それ以外の場合、数字をそのまま返す
# f.FizzBuzz関数を出力する
- コードが書けました。これを確認してみましょう。今回確認することは「FizzBuzz関数が定義できているか」を確認します。このままでは確認ができないので、定義した関数が呼ばれていることを確認できるようにします。以下のように、関数が呼ばれたらコンソールに呼ばれたことを追記すれば良いでしょう。
a.数値を引数に取るFizzBuzz関数を定義する
# a.数値を引数に取るFizzBuzz関数を定義する
def fizz_buzz(n)
+ p 'fizz_buzz定義の確認OK!'
end
# b.15の倍数の場合、FizzBuzzを返す
# c.3の倍数の場合、Fizzを返す
# d.5の倍数の場合、Buzzを返す
# e.それ以外の場合、数字をそのまま返す
# f.FizzBuzz関数を出力する
+ # a.の確認
+ p fizz_buzz(1)
- このファイルを実行した後に以下のようにコンソールに出力されれば「a.数値を引数に取るFizzBuzz関数を定義する」が動いていることを確認できます。
- これで①〜③の1サイクルが終了です。自分が実装しやすいコメントの部分を次に実装していきましょう。
"fizz_buzz定義の確認OK!"
確認中にエラーが出た場合
人によっては以下のようにエラーが出てしまうかも知れません。
fizz_buzz.rb
# 以下のようなファイルを実行した
# a.数値を引数に取るFizzBuzz関数を定義する
Def fizz_buzz(n)
p 'fizz_buzz関数の定義の確認OK!'
End
p fizz_buzz(1)
エラーが出た例
# 以下のようなエラーが出た
fizz_buzz.rb:2:in `<main>': undefined local variable or method `n' for main:Object (NameError)
Def fizz_buzz(n)
- ここでエラーが出ても恐れる必要はありません。あなたは今「a.数値を引数に取るFizzBuzz関数を定義する」としか戦っていません。エラーの原因は確実に新しく追加した処理の中にあります。
- エラーに
fizz_buzz.rb:2
とエラーの発生箇所があり、エラーの最下部にDef fizz_buzz(n)
が表示されているので、ここでエラーが発生していることがわかります。 - 少し分かりづらいですが、今回は以下のように関数定義の文法に大文字が混在しているのが原因でした。この方法の最大のメリットは「必ずタイマン勝負に持ち込めるためミスに気づきやすい」 ことです。
- Def fizz_buzz(n)
p 'fizz_buzz関数の定義の確認OK!'
- End
+ def fizz_buzz(n)
p 'fizz_buzz関数の定義の確認OK!'
+ end
関数定義の確認までする必要があるのかについて
- 上記を見て「ここまで確認するよう必要ある?」と思った方もいると思います。結論から言いますが、このレベルの細かい確認までやったほうが良いです。
- 経験者でも別言語から切り替えた瞬間にこの手のエラーは発生し得ます。動く関数を定義していることを確認する作業は、開発に慣れていないうちは予想以上に重要な作業です。
- この確認を飛ばした場合にエラーと遭遇するとどうなるかはこちらに示しています。
fizz_buzz.rb
# RubyのコードなのにJavaScriptの関数定義をしてしまっている!
function fizz_buzz(n) {
p 'fizz_buzz関数の定義の確認OK!'
}
p fizz_buzz(1)
最終的に出来上がるコードのイメージ
- 上記のサイクルを回して最後に出来上がるコードのイメージは以下のような感じです。
- こんな感じで、日本語コメント→処理が繰り返されている形が完成形です。
- ちなみに、日本語に対応する処理は1行でなくても問題ありません。3行〜5行程になることもあるでしょう。
- ※自分のレベルが上ってきて、日本語コメントがなくてもコードが読める・書けるようになったら、コメントは消しちゃいましょう。
fizz_buzz.rbの完成形
# a.数値nを引数に取るFizzBuzz関数を定義する
def fizz_buzz(n)
# b.15の倍数の場合、FizzBuzzを返す
if n % 15 == 0
"FizzBuzz"
# c.3の倍数の場合、Fizzを返す
elsif n % 3 == 0
"Fizz"
# d.5の倍数の場合、Buzzを返す
elsif n % 5 == 0
"Buzz"
# e.それ以外の場合、数字をそのまま返す
else
n
end
end
# f.FizzBuzz関数を出力する
puts fizz_buzz 2
puts fizz_buzz 3
puts fizz_buzz 5
puts fizz_buzz 15
この実装方法のデメリット
コードを書く作業に至るまでかなり時間がかかる
- 最初のうちはコードを書くまでにかなり時間がかかります。
- そのため、上記のFizzBuzzくらいの簡単なコードから始めて、この実装方法自体にまず慣れるのもありです。
- やってみるとわかると思いますが、①の日本語化のステップがびっくりするくらい時間がかかります。最初は1,2時間の時間で区切ってやったほうが良いです。
- 矛盾するようですが、最初のうちは「方針立てすること」よりも 「ひたすら手を動かしてコードを書く」ことのほうが大事 だったりします。なんとなくコードが書き始められそうなら、少なくとも 「頭真っ白」からは進んでいる証拠なので、コードをガンガン書いてください。
この実装方法のメリット
- いっぱいあります。
実装的な面
1. 可読性の高いコードになりやすい
- ②のコードを書くステップで書けるコードは、「自分が読めるコード」になります。①の言語化のステップが適切に行われている場合、1行1行のコードは短いものになりやすいです。
- 1行のコードであれこれ操作する読みづらいコードになりづらい、ということです。
- 1行のコードで行われる処理が自ずと減るので、最終形はコメントがなくても読みやすいプログラムになりやすいです。
- プログラムが完成した後、「ここまとめられるかも?」というアイデアが出てきたら複数の処理を1行にまとめてみても良いでしょう。
2. ログを見る習慣がつく
- この実装方法では「確認する」作業を頻繁に行います。確認作業をするということは、それだけコンソールに出力されるログの情報を見る機会が増えます。
- 今後のエンジニア人生で「ログを見る」という作業は切っても切れないものです。 英語ばかりで最初は強面に感じますが、ログは色んな情報の宝庫で今後あなたの強い味方になってくれます。
- 実務でもエラーが発生した場合や、バグが発生した場合等は必ずログを見ます。この実装方法では、その ログを見る習慣が強制的につくので自然とエンジニア力が上がっていきます。
- 「思い通りの出力になっている」、「エラーが出てしまった。どんなエラーだろう?」、どんな出力でもログを見ることで多くのことを学ぶことができます。
3. エラーに対処しやすい
- この実装方法では、1つの処理を書いた後に必ず確認するようになります。追加した処理1つによってエラーが引き起こされていることがほぼ確定します。エラーの原因のスコープが自ずと狭くなるので、エラーの原因究明がやりやすくなります。
(参考)2つ以上の処理を同時に実装した際にどんな事が起きうるか
- 上記のFizzBuzzのa,bの実装を同時に行ってエラーが発生した例をお見せいたします。
- 雰囲気としては、「FizzBuzz関数実装して、1つ目の条件分岐を実装できた!いったん動作確認してみよう!」というようなシチュエーションです。
- あなたは、発生したエラーからすぐに原因を究明できるでしょうか?
2つの内容を同時に実装してエラーが発生した例
# a.数値nを引数に取るFizzBuzz関数を定義する
Def fizz_buzz(n)
# b.15の倍数の場合、FizzBuzzを返す
if n % 15 == 0
'FizzBuzz'
end
# c.3の倍数の場合、Fizzを返す
# d.5の倍数の場合、Buzzを返す
# e.それ以外の場合、引数の数値をそのまま返す
End
# f.FizzBuzz関数を出力する
p fizz_buzz(15)
'FizzBuzz'が出力されてほしいのに、以下のエラーが発生してしまった…
fizz_buzz.rb:2:in `<main>': undefined local variable or method `n' for main:Object (NameError)
Def fizz_buzz(n)
-
fizz_buzz.rb:2
の記載があり、Def fizz_buzz(n)
が最下部に表示されているため、エラーに慣れている方はこの行に原因があることがわかると思います。- ちなみに、こちらと同じように「a.数値nを引数に取るFizzBuzz関数を定義する」での関数定義の文法が間違っているのが今回のエラーの原因です。
- しかし、
undefined local variable or method 'n' for main:Object
のエラー文だけを読むと、「変数nが定義されていない」というような内容のみが表示されています。 - ありがちがなのが、ログを見ることに慣れておらず関数定義部分がうまくいっていると思い込み、「b.15の倍数の場合、FizzBuzzを返す」で実装した処理内の
n
が関わる部分でエラーが発生している とエラー文の情報から思いこんでしまうケースです。 - このように複数の内容を同時に実装してしまうと、どの処理が引き起こしているエラーかの原因究明が難しくなります。 原因を誤認するケースも発生し得ます。結果的にデバッグやエラーの解消に時間がかかりやすくなります。
学習面
1.①のステップで日本語化したものが実質TODOリストになるので、実装の全体感が見える
- 日本語化してコメントとして書いたものは実質TODOリストになります。コメントの訳となるコードをそのまま記入していけば、該当機能の実装が完了します。
- コメント化すると「予想より意外と条件分岐多いな」等、パッと見の実装のイメージより具体化されたイメージを持って実装を進めていくことができます。
2.自分がわかっていないポイントがはっきりするので再インプットがやりやすい
- やってみるとわかりますが、日本語化しやすいところと日本語化しづらいところが出てきます。 日本語化しづらいポイントはインプット不足の証拠です。再インプットするなり、簡単なコーディングの問題集を解いて演習を挟んだりするのも全然ありです。この段階で再インプットなしで実装進められたら、「プログラミング向いてるかも」と自信を持って良いです。
- ちなみに、なにか教材をインプットした後に実装を進めている場合、この段階のインプットは一番最初に教材をインプットした際とは全く異なる作業となっています。
- 一番最初は「どこが重要かわからない状態でとりあえず教材に取り組む」状況に近いですがと思いますが、再インプットは「実装の中でXXの処理が弱点と気づいたから読み直してる」 という段階にランクアップしています。
- これは自走してPDCAが回せるようになっているということです。
3.何の進捗もない日ができにくい
- 実装課題は難易度が高いので、無策で挑むと 「やっば、1日考えたのに何も進んでない」 という事が平気で起こります。
- 実装イメージをコメントに書き起こさず機能単位で漠然と実装を進めていると、進捗が上がっているのか上がっていないのかわからなくなるときもあります。
- この実装方法では、一番最初に自分が実装する手順をコメントとして記載しているので、一つのコメントの処理が実装できれば前進していると自信が持てます。
- 言い方を変えると、実装を進めて「実装が進んでいるかわからない」と感じる場合、①のコメント化の内容が間違っているか、粒度が大きすぎる場合が多いです。
- 「今日はaのコメントを実装しよう」、「今日は時間があるからb,cの2つをやろうかな」等実装のマイルストーンも置きやすいです。進んでいる感があるので、挫折も起きにくいでしょう。
- gitを使っている場合、コメント一つを実装するごとにcommitを1つするというのもオススメ です。
4.この方法を続けていると自分の成長を感じやすい
- 筆者もすべての実装でこの実装方法を使うわけではありません。理由は、この実装方法は効果的ではあるものの時間がかかるからです。
- また、この実装方法を続けているとコメントを書かずとも頭の中で実装手順を想像しながら実装を進められるようになるので、コメントを書く必要がないケースが増えてきます。
- この実装方法を徹底しながらいろんな課題に取り組むと、「前はコメントを書かないと実装できなかった処理をコメントなしで書ける」瞬間が来ます。
- この瞬間が訪れると、コメントというサポート無しでコードが書けているということなので成長を強く感じられます。「前はコメント必要だったけど、今はコメントいらない。成長してる!」と感じられるということです。
- 恐らく上記の例題のFizzBuzz問題はコメント無しで書ける人が多いでしょう。それはFizzBuzz問題が、実装手順が想像しやすいものだからです。
- この実装方法を続けていると、FizzBuzz問題レベルに感じる実装の範囲が自分の中で広がっていくのを体感しやすいです。
5.質問がしやすい
- あなたがプログラミングスクールに所属している・実務として実装に取り組んでいる・メンターがいる場合、いざとなれば質問可能な状況だと思います。
- 質問をする際に、上記した「コメント+コード」の組み合わせになっていると、とても質問がしやすいです。また、回答者も回答がしやすいです。
- 例えば、「b.15の倍数の場合、FizzBuzzを返す」の実装を進めていて「15の倍数の場合」のコードの書き方が分からなかったので、「質問したい!」となったとします。
実装していてどうしてもわからない場所が出てきた
# a.数値nを引数に取るFizzBuzz関数を定義する
def fizz_buzz(n)
# b.15の倍数の場合、FizzBuzzを返す
if 15の倍数 # ←ここが思いつかない!
"FizzBuzz"
end
# c.3の倍数の場合、Fizzを返す
# d.5の倍数の場合、Buzzを返す
# e.それ以外の場合、数字をそのまま返す
end
# f.FizzBuzz関数を出力する
- この際、そのまま回答者に質問を投げられる状況が整っています。
- 上のコードをそのまま質問として貼り付ければ、回答者はとても回答がしやすいです。以下を全て満たしているからです。
- 質問者が実装したい処理全体の流れがコメントで記載されている
- 質問者が実装したい内容一つ一つに対応したコードがコメント直下に記載されている
- 処理全体の流れでおかしな点があればコメントを貰えますし、「どの実装箇所のコード化ができなくて質問しているか」がひと目でわかります。
- 上のコードをそのまま質問として貼り付ければ、回答者はとても回答がしやすいです。以下を全て満たしているからです。
6.ググりやすい
- 処理を分解した内容がコメントとして記載されているため、ググりやすくなります。
- 例えば、「b.15の倍数の場合、FizzBuzzを返す」の部分の処理が思いつかなかったとします。
- この場合、ググって解決したくなるケースもあるでしょう。一度日本語に分解して「15の倍数の場合、FizzBuzzを返す」とコメントを書いているため、ググる際にも「ruby 15の倍数 書き方」等コメントの内容ほぼそのままでググることができます。
- 「FizzBuzz問題」という大枠の機能ではなく、「15の倍数の場合、FizzBuzzを返す」という内容まで不明点が分解できているため、自分が知りたい内容とマッチしたものを引き当てやすいです。
- 今回はFizzBuzzという有名な問題が例なのであまり有用性がありませんが、例えばECサイトの「カート機能」やSNSでの「投稿機能」といった機能の実装の場合、機能単位でそのまま検索をしても細かな仕様にそのままマッチしているものは見つかりづらいです。
- 「カート機能」の実装で、「xxの場合、カートレコードを取得する」と日本語で分解した上で「レコードを取得する」の処理が思いつかなかった場合、「Rails レコード取得」のようにググれば自分が探したいものにマッチしたものを引き当てやすくなります。
まとめ
- 長くなってしまいましたが、以上が本記事で紹介したかった実装方法です。この方法を徹底することによって、実装課題に全く対処できないという状況には遭遇しづらくなるでしょう。
- 前述しましたが、本記事で紹介した手法も実装方法のひとつであり唯一解ではありませんので悪しからず。
- また、この実装方法で進めると「言語化する」という作業が一番難しくトレーニングが必要な作業であることに気づくでしょう。