Размер видео: 1280 X 720853 X 480640 X 360
Показать панель управления
Автовоспроизведение
Автоповтор
1つめは、Date型を二つ取る「年齢を計算する関数」を定義するのが良いと思います。まず、to_iした整数値を受け取るようにすると、せっかくの日付を示すデータですよというラベルが消えてバグの温床になります。次に、"today"を固定しないことで、この関数のテストが書けるようになり、また、同じ関数で「この日には既に成人していたね」などの処理が行えます。(そして、さらにその関数を利用して student/customer 変数の実際のクラス(たとえば Person)で age などという getter を作るかどうかなどの議論になります)
3個目はバグが混入してるので修正前のほうがマシ複数桁や文字の場合に修正前と異なる動作になる
マシっていうか仕様の変更なのでダメですね。
@@shogodandy7058 これは合意を取って仕様の方を変えた方がいいのでは、と思いました。
0:31 厳密には誕生日の前日に年齢が上がる8:34 動かない(?)
プログラマ・エンジニアはマジでリーダブルコードを読めって思う
@@hgdyhctiodedgi 1番近いのはコードのレイアウトかな。内容的には名前が具体的かつ誤解されない名前か、とかコードの書き方が目に優しいかつ一貫性があるか、必要なコメントが簡潔に書かれているか等に重きを置いている本だから。ネストを浅くするとか、読めばわかるコメントは書かないっていうことも書いてた。無理やりことわざに当てはめるなら「辞は達するのみ」を地で行く内容、なのかも
1問目student とcustomer は多分同じクラス(person?)なのでageというプロパティを持たせて引き算すればいいしたら、この関数のreturn式を呼び出し側に直に書けばいいだけだし意味もわかる関数として抜き出すにしても、引数はperson1とperson2で充分。別クラスなら分けた意味あるけど2問目&の論理式で全部合致したらtrue、それ以外をfalseの方が読みやすい。途中returnは例外投げるわけでもないならgoto文感があってイマイチ3問目型を変えるだけなら言われてる通り関数いらない4問目何番目とか関係なくパラメータをparseしてリストを返す関数にした方が役に立つ言語の性質や、ダメコードを抜き出す意味もあるかもしれませんが、そもそも関数化が悪手に見えるやつがほとんどなのでひっかかりました
自分の会社はITの会社ではないのでレビューできる人がいません。すべて独学なのでこういった簡素なコードのレビューがとても参考になります。
コードレビューで最低限このレベルの指摘をされないようにしなければ。
四問目は、自分なら正規表現で検索してmatches[1]を返します
num_str_add() の時に「文字列だけど数値として扱いたい」って発想がある人は「自分がそう思うってことはそういう機能が用意されてるのでは?」ってところまで考えて調べてみると良いと思う。エンジニアはみんな楽したい(便利に、不具合を減らすために)からそういう単純なものはほとんど用意してくれてるので。
最後に言ってた、「人格を否定しない」、「小技マウンティングしない」はまさにその通りだと思います。読みやすくて修正しやすいコードがいいですね!!
否定しても、アグレッシブプログラマーのケンカ勃発するだけねこ
1問目は student.birthday と customer.birthday の部分がポリモフィズム働かせられるので to_i で渡すよりは共通化のためのローカル関数作ってポリモフィズムで切り替える方が好きです!3問目の話で言うと左辺に what 、右辺に how 、コメントに why を意識するとコード自体も宣言的になって可読性上がりますね!
3つ目は安易に置換え過ぎかなと思います。引数の型と1から9までというところはチェックしなければいけないのではと感じます。
このシリーズ好き過ぎる
いつも動画楽しみにしております!splitで配列から要素を取得する時にfirstだとパラメーターではなく、ドメインを取得してしまうのではないでしょうか?
こういうコメントと処理が矛盾していることより、バグが検出できるパターンもあるからコメントはなるべく要ると思う。バグ入りコードの場合、コメントないと何やってるかコードかわからない。
だからこそ変数名に気を配るべきという話で、query_paramsとかにしておけばコメントなしでもバグにきづけるはずなんすよね
@@buracky ちゃんとs付けててエラいs付けないとパラメータ群なのか一個だけなのかハッキリしないわparameterは短い関数だからparamのままでいいんじゃないかなparameters_keyとかいう変数名もkeyとvalueのペアだから適切じゃないし
サムネ見て来ました! 嫌味っぽくなってしまうかもしれませんが、3問目のnum_str_add関数は最初の仕様が1~9までしか定義されていないので処理前に引数のnum_strが 「"1", "2", ... , "9"」に内包であることを確認しないと仕様を満たさないのではないでしょうか。またこのエラーチェック処理を入れないとto_iメソッドで数値以外の文字列が来た時に例外となる気がします。間違っていたらすみません。 せっかく関数化したのであれば、チェック機構を入れることでより堅牢なコードになるかと思いました。(動画内で話されていた本来1行で終わる処理を関数化する意味も出てきます。) でも、この動画自体のコンセプトが初学者向けのようですので、処理を増やすことはかえってわかりづらくしてしまう可能性がありよくないかもしれません:)
わたしもそう思いました!elseに含まれる箇所への配慮が必要だと思いました。①1未満の場合(0,-1など)②9より大きい場合(11,12など)③小数の場合(1.8など)④数字以外の場合(A,@など)など色々ありますよね。。
キャスト後の値をチェックしてから足すべきですね
個人的に3問目は呼び出しの前後関係がないと難しいなと思う。関数名と引数名にnumがはいってるからキャストしてるんだと思うけど、もしも渡された引数が数字じゃなかったらどうするんだろうか。それは考慮しなくていいのか?
コメントは処理の内容じゃなく意図を書く、っていうのは人のソースを読むと気が付くことが多い実務やってると実際意図のわからない処理が結構ある
1問目は日付のライブラリを使えって思っちゃうかなあ〜確かに10000で割れば上手くいくけどいいコードとは思えない
二問目 (python)def has_membersip_status(user): return user.is_paid and user.is_active and not user.is_resign
三問目def num_str_add(num_str, original_num): num = int(num_str) if num_str
「コメントは意図を書け」っていうのはホンマそう(別に処理の内容も書いても良いけど)。これはプログラムだけではなく設計書もそうですよね。設計書に「〇〇に××を設定する」とかだけ書かれても、だから何やねん?とかなる。それに後から読んだ時に当時のこととか忘れてるから、????ってなるし・・・。
めちゃくちゃこういう動画おもしろいです!欲を言うと、どういうふうに改善するかをビフォーアフターとして画面上に改善後のコードも表示すると視聴者はよりこういう系の動画は参考になるのではないかなって思いました!今後も活動応援してます!
10000で割ると年齢が計算できる仕組みは、例えば今日=20221106生徒の生年月日=19761201の時、2022.1106-1976.1201=47.9905整数部分を引っ張ると47.9歳。と年齢が分かる。少数部分も使える。みたいな感じですね。結構便利なので僕もよく使うのですが、何か他にいいコードありますか?
なるほど〜。年を整数、月の大小を小数部分で比較することでまとめて計算できちゃうよってことですね。月や日が2桁であることという見えづらい前提によって成り立っているので万が一、月や日が3桁を取りうるよう仕様が変わったとき(そんなことになるなんて想像もつかないですが)はバグになりますよね。なので、処理をまとめているのでその意図をコメントにまとめ、今のカレンダーの形式に基づいていることを許容できるなら問題ないと思います。Webサイトみたいな数十年使うことを見越していないシステムなら大抵大丈夫ですね笑
@@ioritobeta6293 いやぁそうなんですよね。実際に計算できるものの、一般化できていない感じはすごい気持ち悪いですよね笑
逆に10000ていう数字持ってこれる方が、言語の汎用性高いし天才に近いんだよな…笑
たぶん、年齢計算はそれがいちばん早いやり方だと思います。(そこまでこだわらなくても良いかと思いますが、整数のまま引き算してから10000で割った方が計算回数は少ないです。)昔のガラケーのアプリなどは日付を(4バイトで表せる)8桁の数値で保存することがあって、8桁の数値から年を出すために10000で割ることが多かった記憶があります。
@@ioritobeta6293 太陽暦の歴史は相当長いので、数十年使用するシステムでもそこまで想定しなくても大丈夫かと思います。
最後の。?でスプリットしてfirstとってきたらクエリパラメータとれなくない?&第一のキーが欲しいなら=のスプリットだけでよくて、&でスプリットしなくてもいいよね。
5:05 2問目ですが、returnの内容をエラーメッセージ or エラーNumberなどにしてもいいかなと思いました!is_paid が falseなときはreturn 'no paid'(または未納を示すエラーNumber)return trueは return 'OK' (またはエラーNumberの0)などみたいにすると、外部から関数を実行した時に「なぜこのユーザーはメンバーシップ対象外なのか?」がわかりやすくなると思います!
もちろん元は問題外ですが、trueの条件のみをandで書いて返す素直な処理のほうが見て分かりやすいと思います。
このチャンネル、とてもためになる!!
いつも見てます。まだまだ初心者なので本当にありがたいです。
コメントは処理の説明ではなくて意図を書け、ってめっちゃできる上司に言われたのを思い出した笑
1行に直したコードは、汎用化したせいで、バグが起こる範囲が大きくなった気がするので、修整をfor文やwhileで留めたほうが良いのではないでしょうか。
1個目、そもそもdateに四則演算があるなら、それ使ったほうが良さそうですね。言語的にできない場合もありますし、日付だけ計算したいから整数にして10000で割って桁落とししているみたいですが
個人的には1つ目のto_iにしたものを渡すのが良いみたいなのは、関数を使う側にめちゃくちゃopinionatedなモノになってしまうので、customerとかみたいな構造を渡す方が分かりやすいと思います。そうでなければ、この関数を叩く回数が増えれば増えるほどそれらの箇所でto_iをしないといけなくなり、処理がまとめられてない状態になりやすいです。
一問目で年齢を求める際には、年だけint変換して差分を求めて、月日比較で-1するかを判断させるのが良いと思いましたが、1万で割るのがメジャーなやり方なんですかね?
処理系による。int型で割り算が切り捨てなら一万で割る方法も使えるが、他言語への可植性を考えて私も年部分の差出して月日部分で調整する方式を使ってる。
最後の問題はバグって無いですか?言語の仕様を知らないですが x.split("y").first っておそらく文字列xを"y"を区切りとした配列に変換して最初のデータを取得するみたいな感じですよね。ってことは url.split('?').firstは文字列として渡されたURLの?より前が取得される為、そこにはパラメータが含まれないのではついでに、個人的な考えですがソースを見る人間が必ずその言語に精通しているとは限らないので、何をやっているかのコメントを記述するのはありかと思います。
はじめまして。私は逆にクソコードしか書きたくないのですが、どうすれば良いのでしょうか?
時間の計算は言語の関数を使って行う方がいい。簡単だからと安易に足し引きで処理すると困るかもしれない。2000年問題。
「リーダブルコード」読め、というコメントがちらほら見られますが、「良いコード/悪いコードで学ぶ設計入門」はどうなんですかね?最近読み始めたので、皆さんの意見聞きたいです
三つ目の関数、関数呼ばれる前に1から9ののときだけ呼ばれるようにしているのか不明だけれども、関数ないだけ見ると、num_strが1から9以外の時なにも返してないですよね? 0くらいの入力は、ありそうですが。
一問目、引数がto_i済みなのが気になりました。あと入力から一意に出力が決まらないのも気持ち悪い(todayも引数で渡したい)と感じました。
pythonだとdateutil.relativedelta があるので年計算は簡単なのですが、rubyには等価なものはないのでしょうか。ActiveSupportとかに入ってる?
前回のアドバイスが私にとって大変役立ちました。感謝しています!
勉強になります。ありがとうございます。
get_first_url_parameters_key() バグってそう。URLの query parameter は ? の後ろだから first ではダメかな?
だよね。区切り文字以降を取得するなら2番目の要素じゃないと。
勉強になります。
1個目の、引数にxx.birthday.strtime~.to_iを渡してしまったほうが良い。というのはケースバイケースかなと思いました。例として、xxのプロパティにageが追加された場合(んなことは無いだろというのは置いておく)、average_ageの処理はxx.ageの総計 / xxの数に変更になりそうです。そうなった場合、average_ageを呼び出している箇所全てで引数を修正しなければなりません。average_ageの責務は平均年齢を計算する。そのプロセスは(どのプロパティを使うかも含め)average_age内に隠蔽しておいたほうがオブジェクト指向っぽいかなと。
xx.ageのプロパティを持っているクラスで、average_ageを計算するメソッドを追加するのがベストな気がしますね。わざわざaverage_ageだけを外だしするのは、xx.ageが必要な責務を担っていないことになりますし。
@@renyskm どうでしょう...。当たり前ですが平均というのは複数の値を必要とするので、単一のageしか持たないxx(動画の例だとstudentやcustmer)にaverage_ageを追加するのは微妙かなと思いました。仮にstudentを配列で持つschoolクラスなどがあれば、そちらに追加した方が自然かなぁと。
@@babybaby7313 おっしゃる通りその方が良さそうですね。schoolクラスの例は、所謂ファーストクラスコレクションに近いですね。
1つ目student.birthday、customer.birthday は日付型だったのに、student_birthday、customer_birthdayは整数型に変わってますね。2000年15月94日みたいな変なデータは入らないのかもしれないですが、素直に日付型を使った方が良い気がします。
このシリーズもっとやって欲しいです。
くそコードなんて、ほんとはないと、思う。ちゃんと結果出したいって必死にコーディングした結果をけなすのは間違いだ。効率的なコードはあっても、完全に正しいコードは存在しない。chatGPTも、同じ見解だと思うよ。どこがわかんないなら、聞けばいいだけのこと。そういった人間の営みが実はコードを磨くって思ってる
そもそも最初のパラメータを取ってくるって動作がが気に入らん。何のためにパラメータに名前つけてんのって話になる。
num_str_add の問題結構面白くて、自明なように見えてこういう実装があるときは速度のためにあえてこうしている可能性もあるから benchmark も噛ませながらやってもいいと思うif でやったり to_i でキャストしたり bytes[0] - 0x30 する、みたいな様々なアプローチを取っていいそういうことやってるとプログラミングの基礎力が上がるからオススメ
いや、まずテスト書かなきゃ。挙動が変わったらどうするんだ。。。
日付を文字列にして、さらに数値にして引き算するという発想が斬新すぎる
最近職場でのプログラミングの機会が減って飢えていたのか、あれよあれよという間に他の動画も沢山観させていただき、凄く楽しませていただきました。プログラマーにとって刺激になるし勉強にもなり、凄く良いチャンネルだと思います!ちなみに改修前のソースと同等の機能にするなら、3問目はnum_strが数値に変換できないケースと10以上のケースを考慮したら良いと思います。
to_iが何やってるかわからなかったけどatoiなのかな?
4つ目もなんか変では?rubyはよく知らないけれど、3行ともsplitしてfirstしてるのに、?のときは後、&と=のときは前をとってくるコメントになってません? でも動画ではうまくいってると言っているし、不思議。
小技マウンティング良くないって言ってる人が、1番マウンティングしてそうな解説だったんだよな〜笑
3つ目 10:38return original_num + num_str - '0'はアリですかね?(C言語民です)
僕はreturn original_num + (num_str & 0xf)派です。
書かれてる言語をよく知らないけどキャストできない文字列来た時の処理ってどこに記述するんだろ
意訳すると「クソコードを是正するという観点にだけ注目してるので、本当はエラーハンドリングとか必要なんですけど省略してます」だそうです。説明がきっちりとはされてないですけどね(途中でそれっぽいことは言っている)。
はう〜❤週末にエンジニアチャンネル3人勢揃い更新とかめっちゃ癒されます(*´∀`)文字列を順番に表示とかなると未だにカメハメ波のようなforネストを書いてしまったりする私です😂
フォントが見やすい
昔、自社製品のコードで、ループで書けば数行で済むところをリニア展開して数百行書いているのを見たことがあるw新入社員研修の課題ではなく、リリースされているプロダクトのコードで(汗)
10000で割るのは笑えますね。20221104 という数字を10000で割ると西暦が数値として得られる・・・という。
それならば、//=とかで整数を返したらと思いました。
最近のPCは高性能でメモリも贅沢に使えるので高級言語のプログラミングもだいぶ考えが変わってきましたね。昔は機械語に翻訳した時になるべく少ない命令、少ないサイクル、少ないメモリを意識してプログラムを書いていました。
今だと分散化、読みやすさ、それとテストのし安さのバランスが上手く取れたコードが良しとされることが多いかな。ただライブラリやフレームワークの開発ではメモリなども多少意識することは大事ですけどね。あと最近のコンパイラはかなり優秀なので、例えクソコードでも単純なコードならかなり最適化されやすいです。
やっぱりマジックナンバーは一気にコードがくそになる原因ですよね~
function end 形式のプログラム言語調べてみたんですが、見当たりませんでした。どの言語で使われてる構文なのでしょうか。自分が把握している範囲だと、functionを使う言語はカッコ{ }を使うことが大半なので、もしRubyを前提としている場合は構文エラーになりそうだなと思いました。8:37
function 〜 endで書かれる言語はJuliaだと思いますよ
@@HundredAndNinetyThree ありがとうございます。書き方が、RubyやPythonに類似してて習得しやすそうですね🤔
@@KM-we9tf 機械学習等のAIの領域でPythonにとって代わる為にPythonの弱点や悪い仕様などを改善して作られたのがJuliaだそうです。ただ、Pythonのライブラリが豊富過ぎてあまり広まって無いように見えます。
@@HundredAndNinetyThree たしかに、認知度が低いというのが記載されてましたね。ライブラリも少なければ、認知度が低いことで解説サイトも少ないという、状況ですね・・・
サムネのコード書いた人、根性論好きそう
castの概念を知らなかったら、ああなりますね。経験って大事かもなのです。知ってるか知らないか。
どの言語で書かれているんでしょうか?
これはRubyかと思います。関数ではdef~endという表記や、ガード節の書き方が特徴的ですね。このチャンネルではソースコード例を出される際、Rubyを使用されることが多いです。ただし、3問目のfunction~endという表記についてはJuliaの書き方になりますね。なので、以下の通りになると思います。1問目 0:29 Ruby 読み手が分かりにくい1行の複雑な計算式→分かりやすい変数名に分けてから計算する2問目 5:03 Ruby ネストが深い条件分岐→ガード節を利用するなど読みやすくバグの温床になりにくいコードへ工夫する3問目 8:29 Julia 文字型の数字である場合加算する関数を条件分岐で→キャストすれば1行で済む4問目 11:00 Ruby 無意味なコメント→無意味なコメントはいらない、もしくは関数の役割のみコメント表記するだけで良いかも
@@blackblue3998 ありがとうございます!Rubyなんですね!
これわざとアホなコード書いてるでしょう。。。
分身の術使ってるのかと思った
コメント結構積極的に書くなー。でも他の人が条件追加した時にコメント更新してくれないんだよなぁ……
全員白Tだと清潔感が増しますね。
9:44 流石にこの書き方はせんやろw
初学者なら全然やると思いますよ
条件分岐覚えたての頃これやった笑
@@tsubasa_km それをさせない為に、キャストの仕方を序盤に記載してる参考書が多いのかなって思った
あーでも、クラスライブラリとか分からんかったら書いちゃうか
プログラミングを専門とするならガンガン省略化するのはmustですが片手間でやってる方も少なからずいて、私はそういう人には治す前の方がわかりやすいかなと思いますよ
コーディングはコミュニケーションなんだよ
リーダブルコード読まないエンジニア多すぎ。
綺麗に書かないことを気にしない現場があるのが原因な気がしますね🤔
クソコード、動けばそれは、神コード🤪
プログラムは、コーディング規約を作って誰が作っても同じになるようにしましょう。変数名は命名ルールを決めて用語として管理しましょう。まぁこの問題は、いつの時代(創成期から)も付きまとう話ですが。ちなみに大昔は、凝ったプログラム(アセンブラ)で処理実行中に条件に合わせてメモリ上の命令コードをプログラム自分自身で書き換え(オーバーライド)てメモリを節約したりとか、バグったときに命令コード書き換え用に使えるパッチエリアをメモリに確保したりとか楽しかったですよ(笑)
1万で割るのは単に6桁の10進数で表された年齢(YYMMDD)を右に4桁シフトして年の部分だけ(YY)を取り出しているのでは?
コメントは現場によって結構違いますよね…設計書(基本・詳細)やPT/IT/ST仕様書も(^^;ドキュメントの粒度も違いがあるので慣れるまでは大変です
全員白い服だとのっぺりした印象を受けます個性あるTシャツを着たほうがいいと思いますよ
最初のやつは、10000はconstで持つ各DATEの値、オブジェクトの値はわかりやすい変数に入れる。2つ目のはコメントがない。なにに対してtrueなのかfalseなのかがわかりにくすぎる。
2のコード、returnを最初に明示するのにtrueだったら後続の処理になるのか。言語設計がいけてないな...😅
whatではなく、whayを書けは確かに
コメントは書いてほしいねえ。最近は後で誰かがreviewするから見やすく、みたいな風潮だが、更に第三者が見るとわけ分からんので。
駄目なところがあるって言いたいのは分かるんですが、”クソコード”という表現が口悪い様に感じます。クソコード書いてる人はどう感じるでしょう?”よくないコード”とかせめて”ダメなコード”というぐらいマイルドな表現にしたほうが…と思います。
社会人一年目ですが、これぐらいは別になんとも思わないですねクソコード書く人は○○のように人格批判までされているなら別ですが、そのようなことも無く口調も穏やかで、解決策として別のコードの書き方も教えてくださってるのでとても助かります。
@@user-matsu-3- 論点が違います。タイトルに”クソ”という口悪い表現がされてる時点で、既に不快。”私は”ですけどね。
口悪い表現の方が、タイトル的にもサムネ的にもキャッチーになり、エンゲージメントが高くなると考えているのではないでしょうか。
@@いご-b1k それはあるかもしれないですね
@@nekoretu すいません。タイトルのみの話をしていると考えておらず、内容についても言及するコメントになってしまいました。タイトルのみで考えても特になんとも思いません。また、「クソコードを書いてる人はどう思う」とあったので、まだ経験が浅くこのようなコードを書いてしまう私目線の考えを記載しました。「私はそう思う」のであれば主語デカいので変えた方がいいかもしれません。長くなってすいません!
クソコードっていうかクソ言語使ってる時点でオワリかな
1問目 strftime('%Y%m%d').to_i というのはこの処理でしか必要のない処理です。こういった応用範囲の狭い処理は狭い領域に閉じ込めておく方がいいです。書き換え後のコードだとこの関数を呼び出す側にもこの処理を書くことになるわけで、書き換え前のコードの方が質は高いと評価します。
あと student / customer というのはここでは対称関係にあるのでこういった場合は one / other などにするとよいと思います
6:45 2問目ですが、user.is_paid?, user.is_active?, !user.is_resign が全て通った時にだけ true を返しているように見えるのと、それらは全て真偽値なので、僕だったら、return user.is_paid? && user.is_active? && !user.is_resign の1行で済ませますね🤔ただ、それだけだと何をしたかったのか若干伝わりづらいので、「user.is_paid? && user.is_active? && !user.is_resign」を一旦変数に入れますね (has_membership_status? = user.is_paid? && user.is_active? && !user.is_resign 等)
ほぼ同意ですが、has_membership_statusという情報はメソッド名に含まれているので変数化するのは省略して良いと思います
@@mokemoke768 おっしゃる通りだと思います最初のコメントを書いた後に、「あれ?これってもはやそもそも関数じゃなくて変数で十分だよな?」って思いました笑笑
それはいわゆる"1行まとめ病"です。 return user.is_paid && user.is_active && !user.is_resignと return false if !user.is_paid? return false if !user.is_active? return false if user.is_resign?では・1行1条件(独立事項)の目視視認性・1行1条件に比べて、1行に複数条件があるとその条件を紐解く労力(負荷)がかかります。また、仕様追加などで後々、条件追加するときに追加容易性(メンテナンス性)が違います。チーム開発では些細なパフォーマンスより優先事項だったりします。他人が読んだり、数カ月後条件追加が発生することを思うと独立事項毎行を分ける方が良いかもと思えてくるかと思います。(ガード節イディオムだと気づけば尚更)もちろんケースバイケースですが、上記のメリット等を考慮すると私がレビューワーなら1行にまとめるのを再度考えてもらいますがどうでしょうか?
@@atlas-luck おっしゃる通りそういう方法もありますので一概には言えません。ただこの書き方はOSSでは当たり前に使われていて、IDEやlinterによっては指摘事項として自動的に書き換えられることも多いレベルのものです。私がレビュアーなら全く逆ですね・・・
@@atlas-luck それはいわゆる"連投病"です。同じ内容なら落ち着いて書くか、一つは消しましょう笑コードもね笑
1つめは、Date型を二つ取る「年齢を計算する関数」を定義するのが良いと思います。
まず、to_iした整数値を受け取るようにすると、せっかくの日付を示すデータですよというラベルが消えてバグの温床になります。
次に、"today"を固定しないことで、この関数のテストが書けるようになり、また、同じ関数で「この日には既に成人していたね」などの処理が行えます。
(そして、さらにその関数を利用して student/customer 変数の実際のクラス(たとえば Person)で age などという getter を作るかどうかなどの議論になります)
3個目はバグが混入してるので修正前のほうがマシ
複数桁や文字の場合に修正前と異なる動作になる
マシっていうか仕様の変更なのでダメですね。
@@shogodandy7058 これは合意を取って仕様の方を変えた方がいいのでは、と思いました。
0:31 厳密には誕生日の前日に年齢が上がる
8:34 動かない(?)
プログラマ・エンジニアはマジでリーダブルコードを読めって思う
@@hgdyhctiodedgi 1番近いのはコードのレイアウトかな。内容的には名前が具体的かつ誤解されない名前か、とかコードの書き方が目に優しいかつ一貫性があるか、必要なコメントが簡潔に書かれているか等に重きを置いている本だから。
ネストを浅くするとか、読めばわかるコメントは書かないっていうことも書いてた。
無理やりことわざに当てはめるなら「辞は達するのみ」を地で行く内容、なのかも
1問目
student とcustomer は多分同じクラス(person?)なのでageというプロパティを持たせて引き算すればいい
したら、この関数のreturn式を呼び出し側に直に書けばいいだけだし意味もわかる
関数として抜き出すにしても、引数はperson1とperson2で充分。別クラスなら分けた意味あるけど
2問目
&の論理式で全部合致したらtrue、それ以外をfalseの方が読みやすい。
途中returnは例外投げるわけでもないならgoto文感があってイマイチ
3問目
型を変えるだけなら言われてる通り関数いらない
4問目
何番目とか関係なくパラメータをparseしてリストを返す関数にした方が役に立つ
言語の性質や、ダメコードを抜き出す意味もあるかもしれませんが、そもそも関数化が悪手に見えるやつがほとんどなのでひっかかりました
自分の会社はITの会社ではないのでレビューできる人がいません。すべて独学なのでこういった簡素なコードのレビューがとても参考になります。
コードレビューで最低限このレベルの指摘をされないようにしなければ。
四問目は、自分なら正規表現で検索してmatches[1]を返します
num_str_add() の時に「文字列だけど数値として扱いたい」って発想がある人は
「自分がそう思うってことはそういう機能が用意されてるのでは?」ってところまで考えて調べてみると良いと思う。
エンジニアはみんな楽したい(便利に、不具合を減らすために)からそういう単純なものはほとんど用意してくれてるので。
最後に言ってた、「人格を否定しない」、「小技マウンティングしない」はまさにその通りだと思います。
読みやすくて修正しやすいコードがいいですね!!
否定しても、アグレッシブプログラマーのケンカ勃発するだけねこ
1問目は student.birthday と customer.birthday の部分がポリモフィズム働かせられるので to_i で渡すよりは共通化のためのローカル関数作ってポリモフィズムで切り替える方が好きです!
3問目の話で言うと
左辺に what 、右辺に how 、コメントに why を意識するとコード自体も宣言的になって可読性上がりますね!
3つ目は安易に置換え過ぎかなと思います。引数の型と1から9までというところはチェックしなければいけないのではと感じます。
このシリーズ好き過ぎる
いつも動画楽しみにしております!
splitで配列から要素を取得する時にfirstだとパラメーターではなく、ドメインを取得してしまうのではないでしょうか?
こういうコメントと処理が矛盾していることより、バグが検出できるパターンもあるからコメントはなるべく要ると思う。
バグ入りコードの場合、コメントないと何やってるかコードかわからない。
だからこそ変数名に気を配るべきという話で、query_paramsとかにしておけばコメントなしでもバグにきづけるはずなんすよね
@@buracky ちゃんとs付けててエラい
s付けないとパラメータ群なのか一個だけなのかハッキリしないわ
parameterは短い関数だからparamのままでいいんじゃないかな
parameters_keyとかいう変数名もkeyとvalueのペアだから適切じゃないし
サムネ見て来ました!
嫌味っぽくなってしまうかもしれませんが、3問目のnum_str_add関数は最初の仕様が1~9までしか定義されていないので処理前に引数のnum_strが 「"1", "2", ... , "9"」に内包であることを確認しないと仕様を満たさないのではないでしょうか。またこのエラーチェック処理を入れないとto_iメソッドで数値以外の文字列が来た時に例外となる気がします。間違っていたらすみません。
せっかく関数化したのであれば、チェック機構を入れることでより堅牢なコードになるかと思いました。(動画内で話されていた本来1行で終わる処理を関数化する意味も出てきます。)
でも、この動画自体のコンセプトが初学者向けのようですので、処理を増やすことはかえってわかりづらくしてしまう可能性がありよくないかもしれません:)
わたしもそう思いました!
elseに含まれる箇所への配慮が必要だと思いました。
①1未満の場合(0,-1など)
②9より大きい場合(11,12など)
③小数の場合(1.8など)
④数字以外の場合(A,@など)
など色々ありますよね。。
キャスト後の値をチェックしてから足すべきですね
個人的に3問目は呼び出しの前後関係がないと難しいなと思う。関数名と引数名にnumがはいってるからキャストしてるんだと思うけど、もしも渡された引数が数字じゃなかったらどうするんだろうか。それは考慮しなくていいのか?
コメントは処理の内容じゃなく意図を書く、っていうのは人のソースを読むと気が付くことが多い
実務やってると実際意図のわからない処理が結構ある
1問目は日付のライブラリを使えって思っちゃうかなあ〜
確かに10000で割れば上手くいくけどいいコードとは思えない
二問目 (python)
def has_membersip_status(user):
return user.is_paid and user.is_active and not user.is_resign
三問目
def num_str_add(num_str, original_num):
num = int(num_str)
if num_str
「コメントは意図を書け」っていうのはホンマそう(別に処理の内容も書いても良いけど)。
これはプログラムだけではなく設計書もそうですよね。設計書に「〇〇に××を設定する」とかだけ書かれても、だから何やねん?とかなる。
それに後から読んだ時に当時のこととか忘れてるから、????ってなるし・・・。
めちゃくちゃこういう動画おもしろいです!欲を言うと、どういうふうに改善するかをビフォーアフターとして画面上に改善後のコードも表示すると視聴者はよりこういう系の動画は参考になるのではないかなって思いました!今後も活動応援してます!
10000で割ると年齢が計算できる仕組みは、例えば
今日=20221106
生徒の生年月日=19761201
の時、
2022.1106-1976.1201=47.9905
整数部分を引っ張ると47.9歳。と年齢が分かる。少数部分も使える。
みたいな感じですね。結構便利なので僕もよく使うのですが、何か他にいいコードありますか?
なるほど〜。
年を整数、月の大小を小数部分で比較することでまとめて計算できちゃうよってことですね。
月や日が2桁であることという見えづらい前提によって成り立っているので万が一、月や日が3桁を取りうるよう仕様が変わったとき(そんなことになるなんて想像もつかないですが)はバグになりますよね。
なので、処理をまとめているのでその意図をコメントにまとめ、今のカレンダーの形式に基づいていることを許容できるなら問題ないと思います。
Webサイトみたいな数十年使うことを見越していないシステムなら大抵大丈夫ですね笑
@@ioritobeta6293 いやぁそうなんですよね。
実際に計算できるものの、一般化できていない感じはすごい気持ち悪いですよね笑
逆に10000ていう数字持ってこれる方が、言語の汎用性高いし天才に近いんだよな…笑
たぶん、年齢計算はそれがいちばん早いやり方だと思います。
(そこまでこだわらなくても良いかと思いますが、整数のまま引き算してから10000で割った方が計算回数は少ないです。)
昔のガラケーのアプリなどは日付を(4バイトで表せる)8桁の数値で保存することがあって、8桁の数値から年を出すために10000で割ることが多かった記憶があります。
@@ioritobeta6293 太陽暦の歴史は相当長いので、数十年使用するシステムでもそこまで想定しなくても大丈夫かと思います。
最後の。?でスプリットしてfirstとってきたらクエリパラメータとれなくない?&第一のキーが欲しいなら=のスプリットだけでよくて、&でスプリットしなくてもいいよね。
5:05 2問目ですが、returnの内容をエラーメッセージ or エラーNumberなどにしてもいいかなと思いました!
is_paid が falseなときはreturn 'no paid'(または未納を示すエラーNumber)
return trueは return 'OK' (またはエラーNumberの0)など
みたいにすると、外部から関数を実行した時に「なぜこのユーザーはメンバーシップ対象外なのか?」がわかりやすくなると思います!
もちろん元は問題外ですが、trueの条件のみをandで書いて返す素直な処理のほうが見て分かりやすいと思います。
このチャンネル、とてもためになる!!
いつも見てます。
まだまだ初心者なので本当にありがたいです。
コメントは処理の説明ではなくて意図を書け、ってめっちゃできる上司に言われたのを思い出した笑
1行に直したコードは、汎用化したせいで、バグが起こる範囲が大きくなった気がするので、修整をfor文やwhileで留めたほうが良いのではないでしょうか。
1個目、そもそもdateに四則演算があるなら、それ使ったほうが良さそうですね。言語的にできない場合もありますし、日付だけ計算したいから整数にして10000で割って桁落とししているみたいですが
個人的には1つ目のto_iにしたものを渡すのが良いみたいなのは、関数を使う側にめちゃくちゃopinionatedなモノになってしまうので、customerとかみたいな構造を渡す方が分かりやすいと思います。
そうでなければ、この関数を叩く回数が増えれば増えるほどそれらの箇所でto_iをしないといけなくなり、処理がまとめられてない状態になりやすいです。
一問目で年齢を求める際には、
年だけint変換して差分を求めて、
月日比較で-1するかを判断させるのが良いと思いましたが、
1万で割るのがメジャーなやり方なんですかね?
処理系による。int型で割り算が切り捨てなら一万で割る方法も使えるが、他言語への可植性を考えて私も年部分の差出して月日部分で調整する方式を使ってる。
最後の問題はバグって無いですか?
言語の仕様を知らないですが
x.split("y").first
っておそらく文字列xを"y"を区切りとした配列に変換して最初のデータを取得する
みたいな感じですよね。
ってことは
url.split('?').firstは文字列として渡されたURLの?より前が取得される為、そこにはパラメータが含まれないのでは
ついでに、個人的な考えですが
ソースを見る人間が必ずその言語に精通しているとは限らないので、
何をやっているかのコメントを記述するのはありかと思います。
はじめまして。私は逆にクソコードしか書きたくないのですが、どうすれば良いのでしょうか?
時間の計算は言語の関数を使って行う方がいい。簡単だからと安易に足し引きで処理すると困るかもしれない。2000年問題。
「リーダブルコード」読め、というコメントがちらほら見られますが、「良いコード/悪いコードで学ぶ設計入門」はどうなんですかね?
最近読み始めたので、皆さんの意見聞きたいです
三つ目の関数、関数呼ばれる前に1から9ののときだけ呼ばれるようにしているのか不明だけれども、関数ないだけ見ると、num_strが1から9以外の時なにも返してないですよね? 0くらいの入力は、ありそうですが。
一問目、引数がto_i済みなのが気になりました。
あと入力から一意に出力が決まらないのも気持ち悪い(todayも引数で渡したい)と感じました。
pythonだとdateutil.relativedelta があるので年計算は簡単なのですが、rubyには等価なものはないのでしょうか。ActiveSupportとかに入ってる?
前回のアドバイスが私にとって大変役立ちました。感謝しています!
勉強になります。ありがとうございます。
get_first_url_parameters_key() バグってそう。
URLの query parameter は ? の後ろだから first ではダメかな?
だよね。区切り文字以降を取得するなら2番目の要素じゃないと。
勉強になります。
1個目の、引数にxx.birthday.strtime~.to_iを渡してしまったほうが良い。というのはケースバイケースかなと思いました。
例として、xxのプロパティにageが追加された場合(んなことは無いだろというのは置いておく)、
average_ageの処理はxx.ageの総計 / xxの数に変更になりそうです。
そうなった場合、average_ageを呼び出している箇所全てで引数を修正しなければなりません。
average_ageの責務は平均年齢を計算する。そのプロセスは(どのプロパティを使うかも含め)average_age内に隠蔽しておいたほうがオブジェクト指向っぽいかなと。
xx.ageのプロパティを持っているクラスで、average_ageを計算するメソッドを追加するのがベストな気がしますね。
わざわざaverage_ageだけを外だしするのは、xx.ageが必要な責務を担っていないことになりますし。
@@renyskm どうでしょう...。当たり前ですが平均というのは複数の値を必要とするので、
単一のageしか持たないxx(動画の例だとstudentやcustmer)にaverage_ageを追加するのは微妙かなと思いました。
仮にstudentを配列で持つschoolクラスなどがあれば、そちらに追加した方が自然かなぁと。
@@babybaby7313 おっしゃる通りその方が良さそうですね。schoolクラスの例は、所謂ファーストクラスコレクションに近いですね。
1つ目
student.birthday、customer.birthday は日付型だったのに、student_birthday、customer_birthdayは整数型に変わってますね。2000年15月94日みたいな変なデータは入らないのかもしれないですが、素直に日付型を使った方が良い気がします。
このシリーズもっとやって欲しいです。
くそコードなんて、ほんとはないと、思う。
ちゃんと結果出したいって必死にコーディングした結果を
けなすのは間違いだ。
効率的なコードはあっても、完全に正しいコードは存在しない。
chatGPTも、同じ見解だと思うよ。
どこがわかんないなら、聞けばいいだけのこと。
そういった人間の営みが実はコードを磨くって思ってる
そもそも最初のパラメータを取ってくるって動作がが気に入らん。何のためにパラメータに名前つけてんのって話になる。
num_str_add の問題結構面白くて、
自明なように見えてこういう実装があるときは速度のためにあえてこうしている可能性もあるから benchmark も噛ませながらやってもいいと思う
if でやったり to_i でキャストしたり bytes[0] - 0x30 する、みたいな様々なアプローチを取っていい
そういうことやってるとプログラミングの基礎力が上がるからオススメ
いや、まずテスト書かなきゃ。
挙動が変わったらどうするんだ。。。
日付を文字列にして、さらに数値にして引き算するという発想が斬新すぎる
最近職場でのプログラミングの機会が減って飢えていたのか、あれよあれよという間に
他の動画も沢山観させていただき、凄く楽しませていただきました。
プログラマーにとって刺激になるし勉強にもなり、凄く良いチャンネルだと思います!
ちなみに改修前のソースと同等の機能にするなら、3問目はnum_strが数値に変換できないケースと
10以上のケースを考慮したら良いと思います。
to_iが何やってるかわからなかったけどatoiなのかな?
4つ目もなんか変では?
rubyはよく知らないけれど、3行ともsplitしてfirstしてるのに、?のときは後、&と=のときは前をとってくるコメントになってません?
でも動画ではうまくいってると言っているし、不思議。
小技マウンティング良くないって言ってる人が、1番マウンティングしてそうな解説だったんだよな〜笑
3つ目 10:38
return original_num + num_str - '0'
はアリですかね?(C言語民です)
僕は
return original_num + (num_str & 0xf)
派です。
書かれてる言語をよく知らないけどキャストできない文字列来た時の処理ってどこに記述するんだろ
意訳すると「クソコードを是正するという観点にだけ注目してるので、本当はエラーハンドリングとか必要なんですけど省略してます」だそうです。
説明がきっちりとはされてないですけどね(途中でそれっぽいことは言っている)。
はう〜❤週末にエンジニアチャンネル3人勢揃い更新とかめっちゃ癒されます(*´∀`)文字列を順番に表示とかなると未だにカメハメ波のようなforネストを書いてしまったりする私です😂
フォントが見やすい
昔、自社製品のコードで、ループで書けば数行で済むところをリニア展開して数百行書いているのを見たことがあるw
新入社員研修の課題ではなく、リリースされているプロダクトのコードで(汗)
10000で割るのは笑えますね。20221104 という数字を10000で割ると西暦が数値として得られる・・・という。
それならば、//=とかで整数を返したらと思いました。
最近のPCは高性能でメモリも贅沢に使えるので高級言語のプログラミングもだいぶ考えが変わってきましたね。
昔は機械語に翻訳した時になるべく少ない命令、少ないサイクル、少ないメモリを意識してプログラムを書いていました。
今だと分散化、読みやすさ、それとテストのし安さのバランスが上手く取れたコードが良しとされることが多いかな。ただライブラリやフレームワークの開発ではメモリなども多少意識することは大事ですけどね。あと最近のコンパイラはかなり優秀なので、例えクソコードでも単純なコードならかなり最適化されやすいです。
やっぱりマジックナンバーは一気にコードがくそになる原因ですよね~
function end 形式のプログラム言語調べてみたんですが、見当たりませんでした。
どの言語で使われてる構文なのでしょうか。
自分が把握している範囲だと、functionを使う言語はカッコ{ }を使うことが大半なので、もしRubyを前提としている場合は構文エラーになりそうだなと思いました。
8:37
function 〜 endで書かれる言語はJuliaだと思いますよ
@@HundredAndNinetyThree ありがとうございます。
書き方が、RubyやPythonに類似してて習得しやすそうですね🤔
@@KM-we9tf 機械学習等のAIの領域でPythonにとって代わる為にPythonの弱点や悪い仕様などを改善して作られたのがJuliaだそうです。
ただ、Pythonのライブラリが豊富過ぎてあまり広まって無いように見えます。
@@HundredAndNinetyThree
たしかに、認知度が低いというのが記載されてましたね。ライブラリも少なければ、認知度が低いことで解説サイトも少ないという、状況ですね・・・
サムネのコード書いた人、根性論好きそう
castの概念を知らなかったら、ああなりますね。経験って大事かもなのです。知ってるか知らないか。
どの言語で書かれているんでしょうか?
これはRubyかと思います。関数ではdef~endという表記や、ガード節の書き方が特徴的ですね。このチャンネルではソースコード例を出される際、Rubyを使用されることが多いです。ただし、3問目のfunction~endという表記についてはJuliaの書き方になりますね。なので、以下の通りになると思います。
1問目 0:29 Ruby 読み手が分かりにくい1行の複雑な計算式→分かりやすい変数名に分けてから計算する
2問目 5:03 Ruby ネストが深い条件分岐→ガード節を利用するなど読みやすくバグの温床になりにくいコードへ工夫する
3問目 8:29 Julia 文字型の数字である場合加算する関数を条件分岐で→キャストすれば1行で済む
4問目 11:00 Ruby 無意味なコメント→無意味なコメントはいらない、もしくは関数の役割のみコメント表記するだけで良いかも
@@blackblue3998 ありがとうございます!Rubyなんですね!
これわざとアホなコード書いてるでしょう。。。
分身の術使ってるのかと思った
コメント結構積極的に書くなー。
でも他の人が条件追加した時にコメント更新してくれないんだよなぁ……
全員白Tだと清潔感が増しますね。
9:44 流石にこの書き方はせんやろw
初学者なら全然やると思いますよ
条件分岐覚えたての頃これやった笑
@@tsubasa_km それをさせない為に、キャストの仕方を序盤に記載してる参考書が多いのかなって思った
あーでも、クラスライブラリとか分からんかったら書いちゃうか
プログラミングを専門とするならガンガン省略化するのはmustですが
片手間でやってる方も少なからずいて、私はそういう人には治す前の方がわかりやすいかなと思いますよ
コーディングはコミュニケーションなんだよ
リーダブルコード読まないエンジニア多すぎ。
綺麗に書かないことを気にしない現場があるのが原因な気がしますね🤔
クソコード、動けばそれは、神コード🤪
プログラムは、コーディング規約を作って誰が作っても同じになるようにしましょう。変数名は命名ルールを決めて用語として管理しましょう。
まぁこの問題は、いつの時代(創成期から)も付きまとう話ですが。
ちなみに大昔は、凝ったプログラム(アセンブラ)で処理実行中に条件に合わせてメモリ上の命令コードをプログラム自分自身で書き換え(オーバーライド)てメモリを節約したりとか、バグったときに命令コード書き換え用に使えるパッチエリアをメモリに確保したりとか楽しかったですよ(笑)
1万で割るのは単に6桁の10進数で表された年齢(YYMMDD)を右に4桁シフトして年の部分だけ(YY)を取り出しているのでは?
コメントは現場によって結構違いますよね…
設計書(基本・詳細)やPT/IT/ST仕様書も(^^;
ドキュメントの粒度も違いがあるので慣れるまでは大変です
全員白い服だとのっぺりした印象を受けます
個性あるTシャツを着たほうがいいと思いますよ
最初のやつは、10000はconstで持つ
各DATEの値、オブジェクトの値はわかりやすい変数に入れる。
2つ目のはコメントがない。
なにに対してtrueなのかfalseなのかがわかりにくすぎる。
2のコード、returnを最初に明示するのにtrueだったら後続の処理になるのか。言語設計がいけてないな...😅
whatではなく、whayを書けは確かに
コメントは書いてほしいねえ。最近は後で誰かがreviewするから見やすく、
みたいな風潮だが、更に第三者が見るとわけ分からんので。
駄目なところがあるって言いたいのは分かるんですが、”クソコード”という表現が口悪い様に感じます。クソコード書いてる人はどう感じるでしょう?
”よくないコード”とかせめて”ダメなコード”というぐらいマイルドな表現にしたほうが…と思います。
社会人一年目ですが、これぐらいは別になんとも思わないですね
クソコード書く人は○○
のように人格批判までされているなら別ですが、そのようなことも無く口調も穏やかで、解決策として別のコードの書き方も教えてくださってるのでとても助かります。
@@user-matsu-3- 論点が違います。タイトルに”クソ”という口悪い表現がされてる時点で、既に不快。”私は”ですけどね。
口悪い表現の方が、タイトル的にもサムネ的にもキャッチーになり、エンゲージメントが高くなると考えているのではないでしょうか。
@@いご-b1k それはあるかもしれないですね
@@nekoretu すいません。タイトルのみの話をしていると考えておらず、内容についても言及するコメントになってしまいました。
タイトルのみで考えても特になんとも思いません。
また、「クソコードを書いてる人はどう思う」とあったので、まだ経験が浅くこのようなコードを書いてしまう私目線の考えを記載しました。
「私はそう思う」のであれば主語デカいので変えた方がいいかもしれません。
長くなってすいません!
クソコードっていうかクソ言語使ってる時点でオワリかな
1問目 strftime('%Y%m%d').to_i というのはこの処理でしか必要のない処理です。こういった応用範囲の狭い処理は狭い領域に閉じ込めておく方がいいです。書き換え後のコードだとこの関数を呼び出す側にもこの処理を書くことになるわけで、書き換え前のコードの方が質は高いと評価します。
あと student / customer というのはここでは対称関係にあるのでこういった場合は one / other などにするとよいと思います
6:45 2問目ですが、user.is_paid?, user.is_active?, !user.is_resign が全て通った時にだけ true を返しているように見えるのと、それらは全て真偽値なので、僕だったら、return user.is_paid? &&
user.is_active? && !user.is_resign の1行で済ませますね🤔
ただ、それだけだと何をしたかったのか若干伝わりづらいので、「user.is_paid? &&
user.is_active? && !user.is_resign」を一旦変数に入れますね (has_membership_status? = user.is_paid? &&
user.is_active? && !user.is_resign 等)
ほぼ同意ですが、has_membership_statusという情報はメソッド名に含まれているので変数化するのは省略して良いと思います
@@mokemoke768
おっしゃる通りだと思います
最初のコメントを書いた後に、「あれ?これってもはやそもそも関数じゃなくて変数で十分だよな?」って思いました笑笑
それはいわゆる"1行まとめ病"です。
return user.is_paid && user.is_active && !user.is_resign
と
return false if !user.is_paid?
return false if !user.is_active?
return false if user.is_resign?
では
・1行1条件(独立事項)の目視視認性
・1行1条件に比べて、1行に複数条件があるとその条件を紐解く労力(負荷)
がかかります。
また、仕様追加などで後々、条件追加するときに追加容易性(メンテナンス性)が違います。
チーム開発では些細なパフォーマンスより優先事項だったりします。
他人が読んだり、数カ月後条件追加が発生することを思うと独立事項毎行を分ける方が良いかもと思えてくるかと思います。
(ガード節イディオムだと気づけば尚更)
もちろんケースバイケースですが、上記のメリット等を考慮すると私がレビューワーなら1行にまとめるのを再度考えてもらいますがどうでしょうか?
@@atlas-luck おっしゃる通りそういう方法もありますので一概には言えません。ただこの書き方はOSSでは当たり前に使われていて、IDEやlinterによっては指摘事項として自動的に書き換えられることも多いレベルのものです。私がレビュアーなら全く逆ですね・・・
@@atlas-luck それはいわゆる"連投病"です。
同じ内容なら落ち着いて書くか、一つは消しましょう笑
コードもね笑