テーマ、知りたいこと
多人数で開発プログラミングや一人でのプログラミングで行うコーディングルールや開発を知りたいです。
背景、状況
現在、Kotlinを初め、今までは別のC#を使っていました。
私の現状ですがラムダ式が読めず、Kotlinの方でもラムダ式をよく使う方のソースコードを見ましたが、全く分からなかったです。
分からない事ですが、ルールに乗っ取ってプログラミングを実際使っているので、そのルールを知りたいと感じ、意見交換を立ち上げました。
前提
趣味でプログラムをする学生です。教えてくれる人はいません。なので、このサイトを使って勉強しています。
三か月後に分かるプログラミングと書きやすいように書いたプログラミングは相反するものではないでしょうか。
分からないので、質問サイトとして、ここで皆様に共有させて、情報を教えていただきたく存じ上げます。よろしくお願いいたします。
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答16件
#1
--- Kotlin スタイルガイド --- https://developer.android.com/kotlin/style-guide?hl=ja
ここのようにガイドをまとめられていらっしゃる場合や自分がプログラミングを作る際に気にかけている事などを知りたいです。
#2
総合スコア10982
投稿2025/06/29 09:58
編集2025/06/29 10:00質問内容に関する質問です。
質問タイトルが「入門者に教えるプログラミング基礎ルール」だったので”あなた(質問者さん)がプログラミング初心者にプログラミングを教えるときの良い方法が知りたい"のかと思いきや、質問文で「多人数で開発プログラミングや一人でのプログラミングで守る決まり事を知りたいです。」とあり、質問タイトルとは異なり”コーディングルールや開発におけるルール”が知りたいのか?となりました。そうだとしてもここで「多人数で開発」と「一人でのプログラミングで守る決まり事」はかなり異なるかと思うので論点はどちらかに絞った方が良い気がします。
さらに質問文を読んでいくと「ラムダ式が読めず」とあり、結局質問者さんの課題はこれか??となりました。
一体何に困っていて何を知りたいのでしょうか?独学についてと他者に教えるのとでは回答が違ってくるかと思います。
もう少し課題を整理された方がより良い回答(意見)が付くのではないでしょうか?
#1の回答と投稿タイミングが被ってしまいました。
そうであれば質問タグに「kotolin」を付けるべきですし、質問タイトル・質問内容ともそのように書かれた方がより良い回答が付くでしょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#3
変更いたしました。大変失礼いたしました
初心者でも行うプログラミング向けの話題、多人数や一人で行うプログラミング言語のコーディングルール、この2点が知りたいです。
ラムダ式はその話の派生としてたどり着きたい箇所であります。
僕自身は一人でプログラムを作り、聞く相手も話す相手もいません。
「多人数で開発」と「一人でのプログラミングで守る決まり事」の共通する部分が知りたいです。
キャメルケース等が良い例かと思います。基礎的な部分でかまいません。
多人数だから、これが絶対で〜。個人だから自由に書けるけどこうだから〜。
とならないよう基礎中の基礎を知りたいです。
三か月後の自分が見ても分かるコードを書くように心がけてみてはどうでしょうか?適切なコメントを入れることも大事なことかと思います。
今、こちらも大切に思っており、c#で作ったプログラミングを3ヶ月後に見直してみます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#4
総合スコア10982
投稿2025/06/29 12:27
現在、Kotlinを初め、今までは別のC#を使っていました。
私の現状ですがラムダ式が読めず、Kotlinの方でもラムダ式をよく使う方のソースコードを見ましたが、全く分からなかったです。
前提の確認です。
あなたは仕事としてプログラミングをしているのでしょうか?それとも趣味でしょうか?
もし仕事として行っていて上記の「Kotlinの方でもラムダ式をよく使う方」が仕事仲間であれば、直接その人へ教えを乞うべきです。第三者にはその人が書いたコードが分かりませんし、その人の本当の意図も分からないからです。
コーディングルールについては開発現場で規約があれば原則それに従いましょう。
個人で趣味ならまずは書きやすい用に書けば良いのではないでしょうか?”こうあるべき”に囚われて勉強が進まないのは悪手かと思います。最初に動作するコードを書いて後からリファクタリングするという手もあります。
三か月後の自分が見ても分かるコードを書くように心がけてみてはどうでしょうか?適切なコメントを入れることも大事なことかと思います。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#5
総合スコア83
投稿2025/06/29 19:32
私の現状ですがラムダ式が読めず、Kotlinの方でもラムダ式をよく使う方のソースコードを見ましたが、全く分からなかったです。
う〜ん、良く分からんなぁ(笑)。
Kotlinは良く知らんのだけど、ラムダ式自体は別に全然ムズいモンじゃない。
関数定義法さえ分かってれば、ラムダ式って「名前が無い、テンポラリな使用目的の関数」以上でも以下でもねぇからさ。フツーに書いた関数と基本同じだし。
もし、それが「読みづらい」としたら、前提としてその言語自体の「ラムダ式の記述法がワケワカメ」って可能性がある。
したがって、
多人数で開発プログラミングや一人でのプログラミングで行うコーディングルールや開発を知りたいです。
コーディングルールは関係ないんじゃない?って思う。
単にKotlinのラムダ式記述法が「貴方のテイストに合ってない」だけ、って可能性がある。
あるいは、単に、高階関数の仕組みが良く分かってない、とかさ。ラムダ式を一番多用する、ってのは高階関数の引数として、だろうからね。
だとすれば、ラムダ式がどーの、ってのもミスディレクションだよな。単に高階関数を勉強しなおしたらいい、って話になるわけですしおすし。
ちなみに、どーしてもラムダ式が嫌だ、って場合、通常だとフツーに関数書いて、その名前を高階関数の引数にぶち込めば悩まないだろ、ってのもあるね。ラムダ式がある、って事は、Kotlinも「関数がファーストクラスオブジェクト」の言語とちゃうんかしら?多分。
要は「自分の読みやすいように」改造出来ると思うよ。分からんけど。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#6
総合スコア27
投稿2025/06/29 22:10
12歳ということで意図がよくわからず、表現も難しいのだとは思うのですが、
kotlinでラムダ式というのは頻繁に使うものでルールがこんな時に使うというのではないです。
よくわからいのであれば文法を勉強して色々書いてみるのがいいのだとは思います。
kotlinでは引数の最後が関数であれば引数ではなく関数の呼び出しで最後に{}を使えば引数として渡せるという特殊なルールがあるのですが、kotlin特有の特殊なルールになります。
コーディングは自由に行えるものなので、シンプルでわかりやすく書ければ一番良いと思いますがどんな時にどんな書き方をするのかというのは失敗を繰り返して学んでいくのが最善じゃないでしょうかね。
例えば作文でも実はいろいろな書き方、語順とかがありますがルールを気にしますか?しないと思います。
実際にはもっと複雑な理由もあると思いますが、多分この質問で聞きたいことではないのだろうと推測します。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#7
私の背景は語れるだけ語ったと思うのでこれで分かっていただけたかと思います。
誰かと共有したプログラムを作った事がありません。
kotlinでは引数の最後が関数であれば引数ではなく関数の呼び出しで最後に{}を使えば引数として渡せる
これは知らなかったです。まだ理解もしてないので、このレベルを分かるよう頑張りたいです。
Kotlinはまだ始めたてですごく階層が多いのと、プログラムのうまい方のGithubを見ましたが何をしたいのか分かりませんでした。
単にKotlinのラムダ式記述法が「貴方のテイストに合ってない」だけ、って可能性がある。
こうならないよう皆様の知恵を借りて頑張りたいと思いました。
質問や意見交換に付き合ってくださった皆々様ありがとうございました。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#8
総合スコア12229
投稿2025/06/30 02:14
ルール
多分,考えるだけ無駄.
ルールってのは何かしらの 理由/事情 があって定められているものである(…ハズ).
ご自身の背景事情的に必要性が無いルールをどこぞから形だけ引っ張ってきても無駄な制約が増えるだけ.
本来やれたことが謎ルールのせいでやれなくなるとか「百害あって一利なし」って感じだし.
興味があるなら,そのルールの 理由/事情 の方を「読み物として」気楽に見たりしてればいいじゃないかな.
そもそも1人でやってるなら他者と決めごとをする必要は無いのだし,一番自由にやれる時期(?)に変なこと考えててもつまらんと思うよ.
三か月後~
特に長期にわたってメンテナンスしていかなきゃならないものを作ってるのでもないならば
「三か月後に読めるか?」なんてのもまずは気にしなくていいと思うけどな.
とにかく「現時点での全力」「現時点でやれる範囲での最善」みたいな取り組み方で良いと思うよ.
どうせそれを三か月後に見たら「何これ,ふざけてるの?」ってなると思うので,そこでいろいろ考えたらいいんじゃない?
(仮に「何これ?」ってならないのだとしたら,その三か月間とくに成長してなかったってことになるよね)
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#10
総合スコア2060
投稿2025/06/30 05:28
いま適当に検索した規約やルール類を提示します。
分野・対象者・適用ケースを絞らずに「皆様が守っているルールや規則などあれば」と言うとこうなります。
データベースオブジェクトの命名規約
https://qiita.com/genzouw/items/35022fa96c120e67c637
データベースの命名規則
https://avinton.com/academy/database-naming-conventions/
わいの考えたさいきょうのコーディングルール
https://zenn.dev/mbao/articles/my_idea_of_the_best_coding_rules
ベストなコーディング規約の作り方
https://qiita.com/tadnakam/items/5d1280559eb75b29847c
社内のコーディングルールを作成しました
https://engineer-blog.ajike.co.jp/coding_rule/
CI/CD開発ガイドライン
https://gitlab-docs.creationline.com/ee/development/cicd/
AWS規範ガイダンス CI/CD について
https://docs.aws.amazon.com/ja_jp/prescriptive-guidance/latest/strategy-cicd-litmus/understanding-cicd.html
AWS の使用に関するセキュリティ監査チェックリスト
https://s3.amazonaws.com/awsmedia/AWS+Auditing+Security+Checklist+Whitepaper_Japanese.pdf
2024年最新のJavaScriptコーディング規約を様々な観点から整理する
https://zenn.dev/kei615ykhm/scraps/ca1a67da3fb571
安全なウェブサイトの作り方
https://www.ipa.go.jp/security/vuln/websecurity/about.html
MozillaのWebセキュリティガイドラインが中々良かった話
https://qiita.com/Sassy1123/items/32fae1d4914333c24eb0
Dockerfile を書くベストプラクティス
https://docs.docker.jp/develop/develop-images/dockerfile_best-practices.html
バッチ処理実装時に考慮すべき事項
https://engineering.mercari.com/blog/entry/20220422-89e520371b/
API 標準設計ガイド・基礎編
https://www.ipa.go.jp/digital/data/jod03a000000a82y-att/api_standard_design_guide.pdf
Linux カーネル開発のやり方
https://www.kernel.org/doc/html/v4.18/translations/ja_JP/howto.html
ソフトウェア開発プロジェクトでのチェックリスト
https://u5soft.jp/post/software-development/
MISRA C / MISRA C++ (車載ソフトウェア業界で使用されている規約)
https://www.fuji-setsu.co.jp/products/LDRA/MISRA.html
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#11
総合スコア10982
投稿2025/06/30 11:27
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#14
総合スコア22
投稿2025/07/01 01:32
私はC#1.0からC#で開発しています。現在C#13.0です。
C#1.0の時代はGenericも無いし、非同期async/awaitも無いし、多値戻りタプル・
・・などなど全部なかったです。当然、糖衣構文の固まりのLINQなんかも当然ない・・
だから学びやすく入口は低かったと思います。逆に言えば現在のC#13.0から学ぶ人は相当苦労すると思います。特にLINQなんか理解が難しいと思います。
出来れば、詳しい人と友達になって教えてもらってください。それが早いと思います。
C#ですが参考になればと思います。
https://ufcpp.net/study/csharp/
以上
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#15
総合スコア83
投稿2025/07/07 07:12
ちょっとマジメに考えてみようか。
実は「コーディングルール」と言われても殆どの人はピンと来ないと思う。
厳密には、コーディングに関しては次の2つがあるんだよ。
- 命名規約(naming convention)
- コーディング規約(coding conventions)
1つ目は変数名とか、関数名とか、クラス名を「どう名付けるか」と言う規約(convention)だな。名前を付ける時、キャメルケース/パスカルケース/スネークケース
/アッパースネークケース/ケバブケース/ハンガリアン記法/ドットケースを使おうぜ、とか言うヤツだ。
例えば良くあるケースとして、クラス名は大文字で始めるキャメルケース、変数名や関数名は小文字で始めるキャメルケースにしましょうよ、と言うアレだな。
実はこの辺の「命名規約」の登場、ってのはプログラミングの歴史で考えてみると結構新しいんだ。そもそも、今の「命名」は「分かりやすい名前にしましょう」だけど、かつてはそうじゃなかった。「関数名も変数名も短ければ短い程良い」って時期が長かったんだよ。
単純に言うと、1990年代後半のIDE(統合開発環境)の普及によって「分かりやすい命名法」ってのが支持されるようになって、それによって「命名規約」って考え方も普及したんだ。
それ以前だと、例えばラインエディタ(一行一行指定して、その行だけ、が編集出来るエディタ)、とか、あるいはWindowsのメモ帳みたいなスクリーンエディタがあっても、自動補完機能なんざ無いのがフツーだったんだよ。
と言う事は、面倒くさい開発環境で自動補完なし、となるとなるたけ短い表記の方がマシって事になるんだ。タイピング量が多くなるのは皆嫌うんだ。結果、意味の明解さより短さ、ってのがこの時期のスタンダードで、例えばC言語のstdio.h
なんかの命名法はこれに由来する。今なら自動補完が当たり前なんだけど、仮にC言語がIDE登場以降に誕生してたら、standard_input_and_output.h
っつー名前になってたかもしんない。
いずれにせよ、自動補完がないような貧相な状況だと命名規約とかあり得ないよな(笑)。
命名規約、ってのは可読性を上昇させましょう、って事だよな。「命名規約によって」名前を見ただけで、その名前を持ってるブツの「機能」を予測出来るようにしたい、と。
まぁ、考え方は分かるんだけど、これにもツッコミしようがある。
第一に、命名規約が煩くなるくらいだったら、じゃあ、それを構文規則に組み込んだプログラミング言語を開発すりゃあエエんちゃうの?とか。
例えば、クラスを大文字で始めるキャメルケースで書く、ってのが規約だとしたら
class FooClass { なんたらかんたら...; }
とかじゃなく、
FooClass { なんたらかんたら...; }
で自動的に「クラスになる」ようにすればエエんじゃないか、とか。
同様に、変数や関数の命名規約がfooVarとかfooFuncとかだったら
var fooVar; func fooFunc(x: integer) { あれやこれや...; return 何とか }
なんて構文じゃなくって
fooVar; fooFunc(x: integer) { あれやこれや...; return 何とか }
で自動的に変数である、とか関数である、とか解釈しろよ、とか。
技術的には充分可能だとは思う。変数と関数をどうやって分けるんだ、って話もあるけど、実の事を言うと、名前空間が一つで、関数がファーストクラスオブジェクトな場合、変数定義と関数定義って分けなくて構わないんだ。理論的にはそうなる。
ただ、知ってる限りで言うと、命名規約そのものがプログラミング言語の構文として組み込まれてる、ってのは見た事がない。ひょっとしたら存在するのかもしんないけど、まぁねぇよなぁ。
一つはそんなプログラミング言語があったとしたらとても窮屈だろう、と言う事。また、プログラミング言語設計者側も「ユーザーの命名権の自由を侵害したくない」と言うのがあるんじゃないか。
結果、やっぱ「命名規約」ってのはユーザー側での草の根運動の枠をはみ出ない、って言い方が出来る。
もう一つは「可読性」ってのを突き詰めた場合、だ。そもそも「使用可能な文字の制限」ってのをどう解釈すんだ、って話が出てくる。
例えば「可読性」とか「視認性」を考えた場合。言語仕様がどうなってるのか、って問題もあるが、昨今の言語実装だとUTF-8前提の処理系が増えてきている。
Kotlin
1>>> var 変数 = 3 2>>> 変数 3res1: kotlin.Int = 3 4>>> fun 関数(x: Int): Int { 5... return x 6... } 7>>> 関数(3) 8res5: kotlin.Int = 3
僕らは日本人なんで、別に日本語使っても構わないんだよ(笑)。「可読性」とか「視認性」を考えれば実はこれが一番良い、って話にならないか(笑)。
こう書くと、「アルファベットがやっぱ一番打ちやすい」「日本語変換だと半角/全角キーが遠いんで打ちづらい」とか言う反論が必ず出てくる。
一方、上に書いた通り、IDE前提だと日本語で打とうと「自動補完」が効く。また、vimみたいなテキストエディタだとEscキーを多用するんだけど、そもそもEscは半角/全角キーより遠い位置にある。それでもある程度の愛用者が存在する、って事が示すのは「キーの位置」ってのは積極的な言い訳としてはあまり成り立ってない、って事だ。
他にもシステム的に、日本語<->アルファベットの切り替えにCtrl + space
ちゅうキーバインドを使う例もあり、「キーの遠さ」は言い訳としては弱くなる。
結局、当たり前の事なんだけど、「可読性」とか「視認性」ってのは慣れの問題が大きいんだ。アルファベット(+ 数値)のソースコードばっか読んでると「いきなり漢字を含む日本語のクラス/変数/関数名を見ると違和感が生じる」ってだけ、の話であり、それは極論「主観」なんだよ。逆に今後、UTF-8頼りのソースコードを書くことに慣れればヘーキで日本語を使うソースコードが増えて将来では問題にならんかもしんない(この辺の事情はフランス語/ドイツ語/スペイン語/ロシア語/中国語/韓国語なんかでも変わらんだろう)。
少なくとも、プログラミング初学者向けの本に良くあるような
kotlin
1var suuti = 0
みたいな、無理矢理ローマ字、なんつー表現をやるくらいだったら、素直に漢字使った方がエエんとちゃうん?とか僕なんかは思ってる(笑)。
他にもこういう例がある。例えば真偽値を返す関数(述語と呼ばれたりする)を書くとして。とある言語では末尾に?
を付ける、と言う命名規約がある。hoge?
とかだよな。非常に明解だ。
ところが、一般的には?
が関数名とかで使えないプログラミング言語の方が多い、んだよ。そういうプログラミング言語だと、接頭辞としてis
を使おうぜ、とかやってる。isHoge
とかだよな。
でも「視認性」から言うと、?
が使える言語ユーザーから見れば大して良くない。逆に?
が使えない言語のユーザーは、?
を使った関数名を見ればギョッとするだろう。
そう、これも「経験から裏打ちされた」主観、なんだ。
プログラミング言語で使える「名前」だと、制限が多い事が良くあるんだ。有名なトコに「数値は使えるけど先頭には置けない」とかだよな。foo1
はアリだけど1+
って関数名はダメ、だとか。
そういう不自由さから「命名規約が作られる」って側面は確かにあるんだけど、要は、「決定的にこれがイイ!」って命名規約の合意ってのは取りづらいよね。そのプログラミング言語で「許される」名前がビミョーに違ったりするわけだから。
とまぁ、それが「命名規約」の話だ。
次に「コーディング規約」に移ろう。
これは例えば、「C言語で{
をどう打つの?」みたいな話で現れる。次の2つだとどっちが「読みやすい(望ましい)」のか?って話だよな。
C
1int foo(int x) { 2 ...; 3 return x; 4}
C
1int foo(int x) 2{ 3 ...; 4 return x; 5}
他にも、最近は見かけないんだけど、こういった書き方もある。
C
1int 2foo(int x) 3{ 4 ...; 5 return x; 6}
外野から言わせれば「んなモン、どれでもエエんちゃうの?」となるだろう。いや、なる(笑)。
ところが、人によるとそれぞれに理や利があるらしい。
結果、こういった事を大マジメに議論する人たちにとっては、こういう「記述スタイルの問題」ってのはフレーム(炎上)の元、なんだ。いわゆる「炎上案件」だよな(笑)。
確かに、複数人で共同してコードを書く、と言った場合、スタイルの統一ってのは望ましいだろう。
一方、「賢い人たち」ってのはあんまこういう事を議論したがらない、んだ。何故なら、上にも書いた通り、このテの議論は性質上「炎上案件」だ。賢い人たちはフレームに加わらない。
実際は、プロはどんなコーディングスタイルにも合わせるだろう。例えばあるプログラマはA社に就業している。A社は自社名義でもソフトウェアを書く一方、下請けもやってる、とする。
ある時、A社はB社から発注を承けた。B社で採用しているコーディング規約はA社のモノとは違う。当然ながらA社とB社のコーディング規約が違っても、A社のやり方をゴリ押ししたりはしないだろう。粛々とB社のコーディング規約に合わせたコードを書く筈だ。それがプロだからね。
自分が納得するコーディング規約じゃないにせよ、プロは状況に合わせるんだ。言っちゃえば「自分の慣れでは読みづらくても」そこに合わせる。徹底的に「社会の歯車」になる。
言い換えると、それが故に、(敢えて呼ぶけど)turnberryクンが「独りでコードを書いている」のなら「自由にやれば?」ってアドバイスに聞こえないアドバイスをするんだよ(笑)。彼らは「他人に合わせなくてはならない」ツラさを良く知ってるから、だ。せめて「自分のプロジェクトなら自分の好きなように書くべきだ」って心底から思ってるハズだ。
ある意味、大人の対応だよな。
別サイトで出てきた話だけど、こういう話があった。
部下には再帰を使わないように厳命している。何故なら自分が再帰を理解出来ないからだ。
本人は冗談めかして言ってたんだけど、これが意味する事はコーディング規約は下手すればマウンティングになりうる、って事だ。コーディング規約ハラスメントだ(笑)。
ある言語Aに慣れているプログラマαがいる。でも会社ではAよりも高機能な言語Bを採用しているとする。言語Bには言語Aにはないファンシーな機能が目白押しなんだけど、「言語Aにない」が故に難読にしか見えない。
結果、言語Bにある「尖った機能」をコーディング規約で「使えないようにしよう」とする。これも結構あり得る話なんだ。
繰り返すが、「可読性」も「難読性」も突き詰めれば単なる主観なんだけど、難読性を理由として「ある機能を使えないようにしよう」なんつーのは愚かな決定だし、そういう決定を出来る人間は、結局「その言語が好きじゃない」んだ。
んなバカな事があるの?とか聞かれれば「ある」んだよ。例えば最近、プログラミング言語「Python」界隈だと「Pythonic」ってのを標語にして活動してる連中がいて、マルチパラダイム言語Pythonで徹底的に「手続き型」の機能のみでプログラムを書こう/書かせよう、ってムーヴメントがある。マルチパラダイムなのにプログラミングする側にスタイルの制限を強制しよう、ってわけだ。
単純に言うと、単に「Pythonのファンシーな機能が理解出来ません」って言ってるだけ、なんだが(笑)。
いや、そうなると、「Pythonic」ってスタイルは単なる同調圧力なだけ、だ。
※: 念の為に一応聞いておくけど、「ラムダ式の多用は難読なので、コーディング規約で制限されるべきじゃない?」とか言わんよな(笑)?もしKotlinでのコーディング規約でそんなのがあったら、それは「良くない規約だ」と言っておく。個人的には、「使える機能を制限するようなコーディング規約はクソだ」と思う。
それより「練習して慣れて」、「難読じゃない」と言う意識へと持っていくべきじゃないか。
反面、Pythonで起きてるPythonicっちゅームーヴメントはそっちの「良くない」方向へ向かってると思う。
まぁ、そういう理不尽なスタイル強制、ってのは山ほどあって、でもプロはそういう中で我慢してやってるんだよな(笑)。
繰り返すけど、「だからこそ」turnberryクンが「独りでコードを書いている」のなら「自由に書いて欲しい」って思ってると思う。いや、マジで「コーディング規約」って正当性はある一方、「悪ではない」たぁ言えないんだよね。「悪になりかねない」と。
だから独りでやってるのなら「自分は何を一番読みやすいと感じるか」手探りで見つけて欲しい、って思ってんじゃないかな。
多分そういう事だと思う。
んで、実用上の話で言うと、例えば「今から新しくコーディング規約を作りましょう」とか言うのってかなりメンドイ、ってのは想像に難くないじゃない?上のC言語の例じゃないけど、{
をどう置くか、とかさ。一々真剣に考えたくない。
特に、個人プロジェクトだとそうなるでしょ。会社で煩いのに、個人でやる際にそんな細かいトコまで決めていられるか、と。
となると、一番良いのは「デファクトスタンダード」があれば、それに則っちゃう、ってのがテだよな。
例えばC/C++/Java向けにはGNU コーディング基準ってのがあって、それに従って書くか、あるいはそれをマイナーチェンジして書いてる人って結構多いんじゃないだろうか。
他にはPythonだとPEP8ってのがある。僕は無視するけど、結構気にして書いてる人も多いんじゃないか。
この辺、デファクトスタンダードに乗る利点は、それが広く使われてるならLint系ツールがあるだろう、って事だ。好きなようにコードを書いて、Lintを走らせれば、「望ましくない」と思われてるコーディングスタイルを性的静的に検出してくれる。
結果、その辺はLintと言うプログラム任せにして個人プロジェクトでは書いてます、って人は結構いるんじゃないかな?そうすれば「個人プロジェクトに於けるコーディング規約」みたいな不毛な議論をせんで済むし。
kotlinだとktlintってツールがあって、自分でコーディングスタイルを決めるのが面倒くさければ、こういうツールに頼ればいいと思う。
あるいは、使ってるIDEが何かは知らんけど、Android StudioとかIntelliJ IDEAだとLint系ツールを既に含んでるかもしんない。通例だと、構文的にエラーではないけど、「望ましくないスタイル」だと💡が出る、とかさ。そこを直せばいいよ、ってのが一目瞭然となっている。
命名規約、コーディング規約の一般論、ってのは以上かな。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
#16
総合スコア83
投稿2025/07/07 17:57
さて、命名規約、コーディング規約に付いての一般論は書いたけど。
ここからは、個人的にやってるスタイルに付いて書いていく。
「これが絶対正解」とは言わないんだけど、少なくとも僕個人ではいっつも「ワンパターンで」これで済ましてる、と言う事だ。
あくまで「参考程度に」って事だ。
僕個人のスタイルを説明する前に、プログラミングにおける「関数の書き方」の大前提を示す。
それは
入力や出力を計算ロジックに混ぜない
と言う事だ。まずはこれを徹底すべきだ。言い換えると「関数から入力や出力は切り離せ」って事だな。
もちろん、入力された値を整形して返したり、あるいは出力の内容を整形して出力するような関数を書くな、とは言ってない。ただし、それらと「計算のロジックを混ぜるべきではない」と言う事だ。
計算ロジックとはどういう事か。それは「あるデータから別のデータを作り出して返す」と言う事が出来る。言い換えると、そこは一種の、データに対する「フィルタ」なんだ。それはそれとして独立させる。一方、入力関数や出力関数にはフィルタの役割は持たせない。
これを大前提としよう。
インタプリタの実装法がソフトウェア作成の基礎
大学でコンピュータ・サイエンスを学ぶと、恐らく「インタプリタの実装方法」を学ぶ事になるだろう。
んで、今からでもインタプリタの実装法を学べれば学んで欲しい。
「インタプリタの実装法」ってのが実は「ソフトウェアの作成法」の基礎なんだ。
ところが、大学でもその辺は強調されないらしい。どうしても「構文解析」辺りが技術的に派手なんで、そっちの方がテクニカルに注目を集めちゃう。「木を見て森を見ず」になっちまうんだよ。
大学で「インタプリタの実装法」を扱うのは、アカデミックだから取り上げられているわけじゃないんだ。本当は「汎用のソフトウェアの作り方」を取り上げる、ってのがネタなんだ。そして「プログラミング言語実装」以上に「汎用的な」プログラムはない。
言語インタプリタは読み込み部(Read)、評価部(Eval)、出力部(Print)をバラバラに作って、それらを組み合わせてループさせる。これをRead-Eval-Print Loop、略してREPLと呼ぶ。
考えてみると、例えばExcelみたいな表計算プログラムでもこの構造に則っている、ってのが分かるだろう。
あるいはアドベンチャーゲーム(ADV)なんかもそうだ。実は構造的に言うと言語インタプリタと全く同じで、いわゆる「エロゲ」でも事情は変わらない。
もっと言っちゃうと、実はコンピュータそのものがインタプリタだ。入力デバイスがあり出力デバイスがあって、それらは独立している。CPUが「評価部」であって、メモリの内容を一行毎(実際はアドレス毎に、ある量「バイト」を)に処理していく。それらの「組み合わせ」が延々とループしてるわけだ。
つまり、ハードウェアと言う「インタプリタ」上でソフトウェアと言う「インタプリタ」が走っている。メタ循環だ。
また、KotlinはJVM(Java仮想マシン)上で動く言語処理系だけど、この「仮想マシン」と言うのは実は技術的にはインタプリタそのもの、だ。Kotlinがソースコードを「コンパイルする」と言うのは、「仮想マシン」と言うインタプリタ上で動作するコードを吐き出す、って意味になる。
こういうのを見ると、interpreters everywhere(どこでもインタプリタ)ってのがコンピュータ及びソフトウェアの本質的な部分なんだ、ってのが分かるだろう。
REPLの実例(数当てゲーム)
毎度毎度同じネタなんだけど、実例として「数当てゲーム」を見てみよう。既にteratailで別の言語で同じネタを2回書いている(笑)。
前提としては、昨今のプログラミング入門で扱う「最初のプログラム」として、いわゆるHello Worldプログラムではなく、「数当てゲーム」と言われるものが扱われるケースが増えてきている。
「数当てゲーム」とは、コンピュータが乱数で1〜100の値を適当に選んで、プレイヤーがそれを「当てる」と言う大変つまらないゲームだ(笑)。ただ、実装が簡単なんで昨今これが良く使われている。
まずはKotlinでREPLで書くとどうなるか見てみよう。
Kotlin
1import kotlin.random.Random 2 3// メッセージ分離方式 4val message = mapOf( 5 "opening" to "Guess the number!", 6 "prompt" to "Please input your guess.", 7 "failure" to "Failed to read line", 8 "guess" to "You guessed: ", 9 "true" to "Too small!", 10 "false" to "Too big!", 11 "win" to "You win!" 12) 13 14// 環境 15data class World( 16 val guess: Int, 17 val secretNumber: Int, 18 val ordering: Boolean? // x < secretNumber なら true, 逆なら false 19) 20 21// 環境の初期化 22fun init(mx: Int): World { 23 println(message["opening"]) 24 return World(Int.MAX_VALUE, Random.nextInt(1, mx + 1), null) 25} 26 27// Read(読み込み部) 28fun readInt(prompt: String): Int { 29 print("$prompt ") 30 return readln().toInt() 31} 32 33// Eval(評価部) 34fun worldGo(x: Int, env: World): World { 35 if (x == env.secretNumber) { 36 throw Exception(message["win"]) 37 } 38 return World(x, env.secretNumber, x < env.secretNumber) 39} 40 41// Print(印字部) 42fun display(env: World): World { 43 println(message["guess"] + env.guess) 44 println(message[env.ordering.toString()]) 45 return env 46} 47 48// Main (REPL) 49fun main() { 50 var w = init(100) 51 while (true) { 52 try { 53 val input = readInt(message["prompt"] ?: "") 54 w = display(worldGo(input, w)) // Read-Eval-Print Loop 55 } catch (_: NumberFormatException) { // 数字以外を入力 56 println(message["failure"]) 57 // w はそのまま 58 } catch (e: Exception) { // 正解時 59 println(e.message) 60 return 61 } 62 } 63}
メッセージ分離方式
ゲームで使われるメッセージは出力関数に埋め込まずに別に纏めておく。連想配列等を利用して設定しておこう。
Kotlin
1// メッセージ分離方式 2val message = mapOf( 3 "opening" to "Guess the number!", 4 "prompt" to "Please input your guess.", 5 "failure" to "Failed to read line", 6 "guess" to "You guessed: ", 7 "true" to "Too small!", 8 "false" to "Too big!", 9 "win" to "You win!" 10)
昔からあるやり方ではあるんだけど、一般化したのは2000年代に入ってから、だ。ネットの普及でソフトウェアが簡単に国際的に流通するようになり、ローカライズの必然性が高まった煽りを受けた事による。
要は「翻訳」する際に出力に埋め込まれたメッセージをアッチコッチ探し回る面倒を避ける為だ。
もっとマジメにやるなら、メッセージだけを別ファイルに保存して、それをソフトの起動時に読み込むようにするんだけど、ここではそこまではやってない。
環境データ
ゲームで持ち回すデータだ。
Kotlin
1// 環境 2data class World( 3 val guess: Int, 4 val secretNumber: Int, 5 val ordering: Boolean? // x < secretNumber なら true, 逆なら false 6)
ここで、ゲームで用いる複数のデータを一つに纏める。通常はアクセスのしやすさから構造体/レコード型を使うだろう。ない場合はクラスを使えばいいし、一般には、Javaみたいな「オブジェクト指向である事を強制する」プログラミング言語じゃない限り、「クラスを使った」からと言ってそれがすなわち「オブジェクト指向でプログラミングをしなければならない」を必ずしも意味しない(もちろんやっても構わないが)。
また、「ゲームで用いるデータを意味する」とは、この環境データをファイルに書き出せば、それは「保存」を意味し、逆に環境データを記述したファイルを読み込めば、それは「ロード」を意味する。
環境データの初期化
ゲームの起動時に環境データを初期化する必要がある。
Kotlin
1// 環境の初期化 2fun init(mx: Int): World { 3 println(message["opening"]) 4 return World(Int.MAX_VALUE, Random.nextInt(1, mx + 1), null) 5}
ここでは単純に、数当てゲームの「答え」を乱数で計算して設定してる。
なお、この初期化関数は環境データを「返す」事が主眼になってるが、一方、最初に書いた「出力を混ぜるな」に違反している(笑)。
単純には、この関数は一種の独立したスクリプトであり、ここで出力を敢えて噛ました方が全体がシンプルになるんでそうしてる。
なおかつ、この関数は環境データ初期化関数な為、「最初に一回しか呼び出されない」。そのため、あんま考えずにハックしても構わない、って判断なんだ。
Read(読み込み部)
ここではキーボード等の入力デバイスから「整数が入力される」前提で入力関数を作成している。
Kotlin
1// Read(読み込み部) 2fun readInt(prompt: String): Int { 3 print("$prompt ") 4 return readln().toInt() 5}
ここがプログラミング言語実装では字句解析プログラムと構文解析プログラムの2つを連鎖させる部分となる。
ただ、一般のソフトでは、それが必要になるケースは稀だろう。ゲームなら尚更、だ。
しかし、仮に必要になったらここで行い、後続する評価器(Evaluator)へ渡すに適切なデータ形式へと入力情報を変換する。
なお、プロンプト出力をここで混ぜるべきなのか、ちと悩みどころではある。「入力は入力だけ、出力は出力だけ」と分けるべきじゃないか。
しかし、そこで極端に理に走るよりは、プロンプト出力は割り切って入力関数の一部とした方が見通しはいい。Pythonのinput
関数なんかはそういう設計になってるし、単純に便利だ。
また、UNIXのC言語用入力ライブラリ、readline
なんかもそういう方針で設計されていて、ある意味「プロンプトの出力を含む」入力機構、と言うのは由緒正しい実装だ。
Evaluator(評価器)
これがゲームで言うトコのゲームエンジンであり、環境データを組み立て直すフィルタだ。
プログラム上複雑化するのはこの部分になり、必要に応じて小分けすべき部分となる。
いずれにせよ、ここがゲームの中核である「処理」を司る部分となる。
Kotlin
1// Eval(評価部) 2fun worldGo(x: Int, env: World): World { 3 if (x == env.secretNumber) { 4 throw Exception(message["win"]) 5 } 6 return World(x, env.secretNumber, x < env.secretNumber) 7}
一般に、評価器は2引数関数だ。第1引数は入力機構(読み込み部)から入力されたデータを受取り、第2引数には環境データを取る。
ここでは入力データが「正解」だった時(環境データのsecretNumberスロットの値と一致した時)、「ゲームオーバー」と言う例外を送出させている。
そうじゃない場合は環境データを新しく組み直し、それを返している。
(「環境データ」はインプレースで書き換えてもいいけど、一応ここではそれは避けている)
Print(印字部)
評価器から送られてきた環境データを参照して適切なメッセージを表示する関数だ。
Kotlin
1// Print(印字部) 2fun display(env: World): World { 3 println(message["guess"] + env.guess) 4 println(message[env.ordering.toString()]) 5 return env 6}
この辺は機能的には簡単だろう。環境データを利用して適切なメッセージを連想配列(KotlinではMap
型)から引っ張って来て表示するだけ、だ。
なお、忘れちゃいけないのは、ここでは評価器が渡してきた環境データを「そのまま」返す事だ。また、先にも書いたけど、出力関数は環境データを書き換えたり変更したりしてはいけない。あくまで「参照するだけ」だ。
Main関数(Read-Eval-Print Loop)
あとはエントリポイント(Main関数)で実際にRead-Eval-Print Loopを実装するだけ、だ。
Kotlin
1// Main (REPL) 2fun main() { 3 var w = init(100) 4 while (true) { 5 try { 6 val input = readInt(message["prompt"] ?: "") 7 w = display(worldGo(input, w)) // Read-Eval-Print Loop 8 } catch (_: NumberFormatException) { // 数字以外を入力 9 println(message["failure"]) 10 // w はそのまま 11 } catch (e: Exception) { // 正解時 12 println(e.message) 13 return 14 } 15 } 16}
入力がおかしかった場合、例外が投げられてくる。それを捕まえてプレイヤーに「正しい入力を促す」。
また、プレイヤーが正解した場合も例外が投げられてくる。その時にはゲームを終了させる。
あとのRead-Eval-Print Loopは簡単だろう。変数w
は環境データを保持していて、Read-Eval-Print Loopによる変数w
の更新によりゲームが進んでいく。
いずれにせよ、これがソフトウェアと言語インタプリタの基本、Read-Eval-Print Loopと言う設計技法だ。
繰り返すが、「数当てゲーム」自体はゲームとしてはつまらない。一方、こういうREPLとの組み合わせだと、「今から学ぼうとする言語」のチェックシートの役割も果たしてくれる。どういう機能を持ってどう書くのか、あるいはどう書くべきか、と言う概形を知ることが出来る。
- 連想配列の類のデータ型は存在するのか?そしてその使い方は?
- ユーザー定義型はあるのか?そしてその使い方は?
- データ型の型変換の方法は?
- 条件分岐の代替でパターンマッチはあるのか?
- 条件分岐は文なのか、それとも式なのか?
- 条件分岐が文だった場合、三項演算子的な代替案はあるのか?
- 例外を投げる方法は?
- 反復はどういう書き方がスタンダードなのか?
- プログラムのエントリポイント記述はどうなってるのか?
- 例外処理はどうなってるのか?
これは「プログラミングに慣れてる人」にとっても有用だろう。「REPLによる数当てゲーム」はプログラムを書く際の、大まかな「良くあるテクニック/良く使うデータ型」に付いて自然と触れている。
最近だと生成AIもかなり賢くなってきてるんで、得意な言語で「数当てゲーム」をREPLで書いて、それを生成AIに翻訳させる事によって「今から学ぶ言語の」要点・注意点をザーッと把握する事が出来る筈だ。
また、GUIの設計技法にMVC(Model-View-Controller)ってのがあるが、実のことを言うと、これはREPLの変種だ。基本的なアイディアは全く同じモノなんだ。
結果、REPLって設計技法さえ分かれば、CLI(コマンドラインインターフェース)からGUIまで、一貫したパースペクティヴでソフトウェア設計と対峙する事が出来る。
最後に、「ループが無いパターン」、いわゆるスクリプトの記述に対して付け加えておこう。ただし、これも「読み込み部」「評価部」「印字部」と分けて書くべきだ。もうちょっと言うと、「読み込み部」の部分は、コマンドライン引数を使った方がいいだろう。
Kotlin
1#!/usr/bin/env kotlin 2import kotlin.system.exitProcess 3 4/** ローマ数字を Int へ変換 */ 5fun romanToInt(s: String): Int { 6 val d = mapOf( 7 'I' to 1, 'V' to 5, 'X' to 10, 8 'L' to 50, 'C' to 100, 'D' to 500, 9 'M' to 1000 10 ) 11 12 // ペア (積算値, 直前の値) を保持しながら右端から畳み込む 13 val (result, _) = s.foldRight(0 to 0) { ch, (valAcc, prev) -> 14 val n = d[ch] ?: error("Invalid Roman numeral: $ch") 15 val newVal = if (prev > n) valAcc - n else valAcc + n 16 newVal to n 17 } 18 return result 19} 20 21/** エントリポイント : 引数 1 個目を変換して表示 */ 22fun main(args: Array<String>) { 23 if (args.isEmpty()) { 24 println("Usage: romanToInt <ROMAN_NUMERAL>") 25 exitProcess(1) 26 } 27 println(romanToInt(args[0])) 28}
詳細は省くけど、これは「ローマ数字をアラビア数字(いわゆるフツーの整数)」へと変換/表示するスクリプトだ。例えば"XLII"を42へと変換する。変換過程はreduce
の亜種、foldRight
を使用している。当然ラムダ式を使ってて、foldRight
+ ラムダ式の実例となる。
その辺はじっくりと読んで解釈してもらうとして、入力はmain
関数内のコマンドライン引数から受け取って計算してから出力している。しかしながら、結果、入力とデータ生成プロセス、及び出力は全て切り離されていて、REPLのLoopが無い「だけの」構造だ、ってのを実感して欲しい。
「やり方は一貫してる」ってのを分かってもらえただろうか。
これが僕が書く際に、いつも「ワンパターン」へと落とし込んでるやり方だ。
参考にして欲しい。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。