Coding
新人プログラマに知ってもらいたいメソッドを読みやすくするいくつかの原則
プログラミング英語検定(これみれば変数名とか付けられる)
コーディング速度をあげるコツ
コーディング速度を上げる一番の考え方は迷いをなくすこと。
共通化したい時の考え方
- 一階層上を作りwrapする
- カリー化で適用する
- abstractで共通処理を抜き出す
リファクタリングについて
マジックナンバーをやめる
number or string どちらもやめるべき。
新規のプロジェクトに入る時の心構え
全体がわかっていないとコードを書くことが絶対わからない。
必ず新規プロジェクトに入った際には必ず仕様やドキュメントをしっかりみること。
プログラムを書く前に考えること
書きながらロジックを構成していくのは上級者。
そうなるべきだが、まずは紙でも良いのでロジックを考える。
ロジックが完成してから書く癖を。
同じことを繰り返すな
コメントの書き方
変数名/クラス名/関数名で明白なことは書かない。
コミュニケーションでの理論で**グライスの公理(Grice’s Maxims)**というのがある。
円滑なコミュニケーションが満たすべき4つの条件を説明している。
- 量の公理(Maxim of Quantity): 情報を過不足なく提供する。
- 質の公理(Maxim of Quality): 根拠のないことを述べない。嘘をつかない。
- 関係性の公理(Maxim of Relation): 関係のないことは述べない。
- 様式の公理(Maxim of Manner): 簡潔に理路整然と述べる。
上記をコメントに落としてみる 以下のようなコメントは、グライスの公理に反しているものが多く、ソースコード上の円滑なコミュニケーションを阻害する。
- 量の公理に違反: コメントを書きすぎている/コメントが説明不足
- 質の公理に違反: コメントが間違っている
- 関係性の公理に違反: コードと関係のないコメント
- 様式の公理に違反: ストレートではなく、まわりくどい、曖昧なコメント
量の公理に違反
それぞれのステップでコメントを書くことは、あまり推奨されていない。
書きすぎると量の公理に違反する。ステップにコメントが多い場合は変数名や関数の切り出し・クラスの分割など検討すること。
良いプログラマーと悪いプログラマーのコメント意識
良いプログラマーは 少数の本当に優れたコメントを書くように務める 理由を説明するコメントを書く 大量のコメントを書くことよりも、優れたコードを書くことのほうに集中する 理にかなった有用なコメントを書く 悪いプログラマーは 優れたコメントとそうでないコメントの違いがわからない 方法を説明するコメントを書く コメントが自分以外には理解できないものであっても気にしない 不適切なコードを支える目的で多数のコメントを書く ソースファイルに冗長な情報(改版履歴など)を大量に盛り込む
正規表現でvscodeを検索する
正規表現を普段から使えるようにするための特訓として、vscodeの検索で使う。
ゲームのランタイムで正規表現を使わないとのこと(負荷が高いパターンなどあるため)
関数を作るのも、クラスを作るのも関心の分離を考えるべき
アプリケーションを3層に分けたとき(プレゼンテーション・ビジネスロジック・データアクセス)をベースに考えるとわかりやすい
ビジネスロジックをデータアクセスと切り離すというのは保存先がファイルだろうと、RDBだろうとドキュメントDBだろうと、保存ができるようにする。
ようは、ビジネスロジックは限定してはいけない(要は保存をかける時にはバリデーションや整形などすべてを気にしなくて良くする)
バリデーションは早めに
status: TicketStatus[]にして、handler側でパースしてしまうのがいいかと思います!
バリデーションはなるべく上の層でしてしまうのがいい。
なるべく早めにバリデーションへかけてしまうことでサーバの負荷も下がるため
コードは今必要なものだけをかく
汎用性よりも単純性を考える。汎用性のもたらす再利用性や拡張性よりもまずは使えることに価値を置く
このパラメーター将来必要だろうとするよりも、今必要な機能の作成に時間をさく
新規の関数を作成するとき、共通処理がないか探す
関数の中で呼び出している処理が、他の関数でも同様の処理がある場合は二重管理となる。
そのため共通の処理として切り出せないか模索する。
新規のクラスを作成するとき、共通のプロパティ・メソッドがあるのであればそれを base として切り出して抽象クラスやインターフェースなどで切り出すことができないか考える
新規のクラスを作成するとき、共通のプロパティ・メソッドがあるのであればそれをbaseとして切り出して抽象クラスとして作成し、違うクラスを2つ作る。
→抽象クラスなどを作りすぎると処理が複雑になり可読性が損なわれる可能性も孕んでいる
参考演算子を使用してもより単純な選択肢が存在しているかもと考える
メモ化を考える
メモ化はNextの <Script> タグがわかりやすい
参考URL
メモ化とは
メソッドが最初に呼び出された時、戻り値がキャッシュされそれ以降同じスコープ内でメソッドが呼び出されるたびにキャッシュされた値が返されることを意味する
メモ化とは同じ結果を返す処理について、初回のみ処理を実行記録しておき値が必要になった2回目以降は、前回の処理結果を計算することなく呼び出し値を得られるようにすること。
すでに起動しているサーバー or Lambdaなど揮発性も考慮すること
イベントハンドラーのようなcallback関数をメモ化し、不要に生成される関数インスタンスの作成を抑制、再描画を減らすことにより、都度計算しなくて良くなることからパフォーマンスを向上が期待できる
わかりやすく 関数はオブジェクトなのでプロパティを持てる。 そのプロパティにその関数の結果を格納しておけば、毎回計算しなくても値として格納しているものを読み込むだけのため速度が速くなるよね。ということ。
メモ化とシングルトンの違い
シングルトンとメモ化は異なる概念であり、使用する場面や目的が異なる
シングルトンは、アプリケーション内でひとつのインスタンスを共有するためのデザインパターン。
特定のクラスのインスタンスが必要な場所で、常に同じインスタンスを取得できるようにする。
シングルトンは、リソースの共有や状態の保持が必要な場合に有用。
一方、メモ化は計算結果を一時的に保存し同じ引数で再度呼び出された場合にキャッシュから結果を返す手法。
メモ化は再計算のコストを削減し、パフォーマンスの向上を図るために使用される。
とくに計算結果が不変であることがわかっている場合や、再計算が高コストである場合に有効。
シングルトンとメモ化は目的が異なるため、どちらが良いかは使用する場面や要件によります。シングルトンはクラスのインスタンスの共有や状態管理が必要な場合に適しており、メモ化は計算結果の再利用やパフォーマンスの向上が必要な場合に適しています。
抽象クラス
抽象クラスを作成することにはいくつかのメリットがある。
抽象クラスはオブジェクト指向プログラミング(OOP)において、クラスの設計とコードの再利用性を向上させるために重要な役割を果たす。
以下に、抽象クラスを作成する主なメリットを説明します。
1. コードの再利用性向上
抽象クラスは共通の機能や属性をひとつの基底クラスに集約し、複数のサブクラスで共有できます。これにより、重複したコードの記述を避けることができ、メンテナンスが容易になります。
2. 一貫性の維持
抽象クラスを使用することで、すべてのサブクラスが共通のメソッドやプロパティを持つことが保証されます。これにより、一貫したインターフェースが提供され、コードの可読性と信頼性が向上します。
3. ポリモーフィズムの実現
抽象クラスを使用することで、ポリモーフィズムを実現できます。これにより、サブクラスのインスタンスを基底クラス型の変数で扱うことができ、動的なメソッドの呼び出しが可能になります。
4. 共通の基本動作の定義
抽象クラスに共通の基本動作を定義し、サブクラスでその動作をオーバーライドして拡張できます。これにより、基底クラスで基本的な実装を提供しつつ、サブクラスで具体的な実装を定義できます。
5. 強制的なインターフェースの実装
抽象クラスは抽象メソッドを含むことができ、サブクラスにこれらのメソッドの実装を強制できます。これにより、サブクラスは必ず特定のメソッドを実装することが保証されます。
複数人で開発を行う場合に実装レベルのルールを作れる
抽象クラスとインターフェースの違い
言語によるが、抽象クラスの多重継承を禁止していることが多い。
上記を踏まえると、抽象クラスは結合度が高くなる(実装するべきmethodなども多い)
その点、interfaceは実装の責任を課す部分もあるが、多重継承も可能のためファイル分割も可能となる。
メモ化とは
メモ化とは同じ結果を返す処理について、初回のみ処理を実行記録しておき、値が必要となった2回目以降は前回の処理結果を計算することなく呼び出し値を得られるようにすること。
分岐アンチパターン
大事なこと
- 否定の否定は回避する(変数名の代入先と代入部分に着目しろ)
- 基本的に変数名は肯定で記述しよう
// アンチパターン
$delete_off = false;
// 両方、否定の否定になっている
// 対策
$delete_on = true
コーディング規約
コーディング規約は多数のプログラマが参加するプロジェクトにおいて、プログラミング品質を均等にするために定める文書
メンバーのスキルが高い場合は、コーディング規約はできるだけ薄い方が良い。高スキル者に色々規約を守らせようとすると生産性が大幅に落ちてしまい高スキル者を集めた意味がない。
再生 vs 再認
認知心理学では、2つの記憶のモード、再生と再認を考える。
- 再生 再生は過去の記憶を何もインプットがなくても思い出せる状態。
- 再認 これは体験したことがありますか?と問われてたらああ、これは体験したことがあると思い出せる状態。
再生するには?
再生をするには完全に完全に記憶しきっている状態にならないとダメ。 慣れている人は、数多くのパターンを記憶しておりそれを再生することでコードが書ける。他の人のコードを見たときにも過去のパターンと照らし合わせてよりよいコードパターンを思いついたりする。
**再認の方が難易度は低い。**ドキュメント、サンプルコード、ネットで調べた情報などを辿りながら、それを組み合わせて実装します。時間もかかりますし、検索で出てこないパターンだとパフォーマンスが落ちる。 ですが、なんどもなんどもコードを見て繰り返し再認していくと、再生でコードが書けるようになります。このドキュメントは再認の効率アップがゴールです。
とはいえ、必ずしも全員が再生レベルになる必要はありません。たとえGoに慣れていても、普段使わないパッケージ(cryptoパッケージの暗号化とか)を使う場合は再認で(サンプルのコピペで)コードを書くことになるでしょう。上級者でも、自分用のスニペット集を作ることで、記憶の能力の節約しつつパフォーマンスは落とさないということをしますね。
コーディングを書き始める前に念頭においておくもの
- 仕様は確認したか?ビジネス要件 & サイトの機能、役割がわかっていないと全体像を見通せない。 そのため全体像を把握していることを考える。
- コードを書き始める前にコメントでその処理をやることを考える。
同じことを繰り返すな(Don't Repeat Yourself: DRY): DRY
ソフトウェア開発上の原則であり「システムを構成する知識のあらゆる部品は、常に単一であり、明確であり、信頼できる形で表現されていなければならない」というもの。 同じコードを繰り返し書くことを徹底的に避けることで、コードが保守しやすくなり、容易に拡張できるようになり、そして何よりバグを減らすことができる。
設定より規約が優先(Convention Over Configuration): Railsでは、Webアプリケーションで行われるさまざまなことを実現するための最善の方法を明確に思い描いており、Webアプリケーションの各種設定についても従来の経験や慣習を元に、それらのデフォルト値を定めています。このようにある種独断でデフォルト値が決まっているおかげで、開発者の意見をすべて取り入れようとした自由過ぎるWebアプリケーションのように、開発者が延々と設定ファイルを設定して回らずに済みます。
論理演算を考えろ(ドモルガンの法則)
!(P || Q) == !P && !Q
!(P && Q) == !P || !Q
const hasUserLicense = !(isSubscriptionFailed.value || isWaitingKonbiniCharge.value);
switch 文
スタイルシート系は抜いて、 網羅できていないものはいい。
switch文では文字を返してはいけない返すのは変数 なぜなら変数を返すだけなら変更の影響は少ないから
そして上司にはこう言える documentを変えたダケのためテストは入りません。 プログラムの動作は変更がないためテストは不要だろう?という話
if文を減らすには
真偽値
オーバーロード
メリット オーバーロードを使う場合、同じような機能で引数にint型とdouble型がある場合でもメソッド名は同じ。 そのため、メソッドを使う人は引数の型を気にする必要がない このようにオーバーロードを使うことで、メソッドを使う人が "引数の型を意識せずに使える"というメリットがありま す。 オーバーロードが使われている身近な例のひとつに「System.out.println()」があります。printlnメソッドは、int, double, Stringなど引数の型が違っても同じメソッド名で使用できますよね。 このように、オーバーロードすれば引数によってメソッドの名前を少しずつ変更する必要がなく、メソッド名を覚える必要もなくなる、などさまざまなメリットがあります。
デメリット オーバーロードの使い方によってはデメリットも存在します。 たくさんオーバーロードしすぎた場合、プログラムの理解がしにくく管理が難しくなってしまいます。またしっかりと設計しないと、同じ名前でもばらばらの処理を行うメソッドが生まれてしまったりして、混乱を招いてしまうこともあるでしょう。 オーバーロードは便利ですが、何にでも使えばいいわけではありません。必要なところを見極めて使用しましょう。
配列から重複要素を取り除く
「Setに渡した値は重複しない」という特性を使って、配列から値が重複する要素を取り除く処理に応用できる。
エラーハンドリング
エラーハンドリングとして、その言語で標準に設定されているものや
const hello = () => {
throw new Error();
}
その言語のErrorインターフェースを満たした独自の型を定義する方法がある。
世界対応なのか日本対応なのか
Time.zone = 'UTC'
Time.zone.now
# => Thu, 04 Feb 2016 10:00:00 UTC +00:00
Time.use_zone('Asia/Tokyo') { Time.zone.now }
# => Thu, 04 Feb 2016 19:00:00 JST +09:00
エラーメッセージは見ろ
しっかりみて検索する力を、GitHubのissueとか探せ
変数名を考える
スカラー型
スカラーとは単一の値のことを示しています。 単一の値ということは複合的なデータではないということです。 つまり、プログラマーにとってわかりやすい単語を使うなら、複数のデータを扱う配列やハッシュはスカラーではありません。
アノテーションコメント
Rubyのstyle guideから Rubyではコードの中からアノテーションコメントを見つけるライブラリがある。
// TODO: 後で追加すべき内容を表す
// FIXME: 修正すべき箇所を表す
// OPTIMIZE: パフォーマンスの最適化をすべき箇所を表す
// HACK: リファクタリングすべき箇所を表す
// REVIEW: レビューすべき箇所を記す
配列と連想配列
配列は単なる値の順列と考えられる。
値が一つ一つ順番に並んでおり、入っている値の数(同じオブジェクトが重複して入っている場合もある)がその配列の長さであり、0または1から始まるインデックスでアクセスできるというものです。複数のオブジェクトをひとまとめに扱う場合、この単純な配列であってもそれなりに使用できますが、インデックスは整数しか使えず、飛び飛びに使うことはできず1、ある値を探すには順番に見に行くしかないなど、色々と不便なところがあります。そこで、インデックスに任意の名前をつけて、目的の値をすばやく取得できるようにしたのが連想配列です。
ソフトウェア的 ConfigとSettingの違い
粒度が違うのは少しわかる。
Configurationは、何かシステムの深く基礎的な属性として感じ取る。 Preferenceは、モノサシの反対側の端に置くと思う。 SettingとかOptionというコトバもあって、そこらへんはどちらでも構わないただし文脈内での一貫性は保ちつつ) Propertiesは大概オブジェクトやアイテムを参照して使うコトバ(例えばグラフィックプログラムにおける画像など) まとめて例示すると、自分がシステムを設計するとして、インストール中に利用者や顧客に設定させるのがConfiguration。(それが済んで)個々のユーザに表面的なことについて独自の選択をさせるためにPreferenceメニュを用意することだろう。で、そのPreferenceの中には山ほどのsettingやoptionが束になってる。何かのオブジェクトを右クリックしたりすると、そのオブジェクトの特徴的な性質を変更するためにPropertiesの変更権を得る。 ただし、最終的には、用語についても、ソフトウェアの他の作り物と同じようにテストすること。こういった呼称については、業種ごとに極めて特徴的な習慣が、まま、ある。柔軟に考えて、混乱を生む要素については直すこと。
管理者権限でいじるのがconfig ユーザー権限でいじるのがsettings
モデルについて
モデルのファイル名やファイル内のモデル名は単数が基本。 モデルを単数にするとテーブル名をmembersのように複数形、モデルのクラス名は単数形のMember、クラスを記述するファイル名はmember.rbとなる。
循環参照
重複を取り除く
言語によって変わるが、配列などをSetにかまして重複を取り除くっていうのはいわゆるテクニック。
Set
Setは特定の要素を出し入れするような用途には適していない。 一般的にSetを利用するのは、ある値がすでに存在しているか(=サブセット)など集合関係に関心がある場合に使用する。
DDD
関数型プログラミング
連想配列と配列
基本的に配列は前から順番に検索するため時間がかかる。 連想配列はインデックスを貼るため検索が早くなる。
enum
大体の言語が boolean・string・integer を提供している。
表現する個数が少ない場合などは integer で表現するのはありだと思う。
4つぐらいから文字列で定義したほうがいいかも
配列操作
考えること
用は配列の中身をランダムに取得すれば良い話。
index部分をランダムにする
Xxx[n~nx]
依存関係を減らす
実際のところ、完全に依存を排除することは少なく、必要な部分だけ依存することが一般的です。多くの開発者は、以下のようなバランスを取っています。
-
必要最小限の依存: プロジェクトに必要な機能を実現するために、最小限の依存だけを取り入れる。余計な機能は使わない。
-
インターフェースの抽象化: 将来的な変更を見越して、主要なインターフェースを抽象化し、ライブラリに直接依存する部分を限定的にする。
-
メンテナンスのしやすさ: 依存を減らしすぎてコードが複雑になると、メンテナンスが難しくなるので、適切なバランスを保つ。
ほとんどのケースでは、必要に応じて依存を最小限に抑えつつ、ライブラリを活用して開発効率を高めることが一般的です。完全な非依存を目指すのではなく、プロジェクトのニーズに応じて柔軟に対応することが大切です。
Tips
- Math.floor() 与えられた数値以下の最大の整数を返す。
console.log(Math.floor(5.95));
// expected output: 5
console.log(Math.floor(5.05));
// expected output: 5
console.log(Math.floor(5));
// expected output: 5
- Math.random() 0以上1未満(0は含むが、1は含まない)の範囲で浮動小数点の擬似乱数を返す
function getRandomInt(max) {
return Math.floor(Math.random() * max);
}
console.log(getRandomInt(3));
// expected output: 0, 1 or 2
console.log(getRandomInt(1));
// expected output: 0
console.log(Math.random());
// expected output: a number from 0 to <1
ユースケース
なんらかの目的を達成するために行われるユーザとアプリケーションの間の一連のやり取りを表したものです
EntityとModelの違い
一般的なソフトウェア開発の文脈では、"Entity"と"Model"は異なる概念を指します。
エンティティ(Entity)は、データベース内の特定のテーブルやコレクションに相当するものです。エンティティはデータベースの実際の構造に基づいて定義され、特定のデータベーステーブルの行(レコード)に対応することがあります。エンティティは通常、データベーススキーマ内の列(フィールド)と1対1または1対多の関係を持ちます。エンティティはデータベースからのデータの永続化や取得を担当する場合もあります。
一方、モデル(Model)は、アプリケーション内で使用されるデータの構造や振る舞いを表現するために使用されます。モデルはエンティティや他のデータソースからのデータを抽象化し、アプリケーションのビジネスロジックや操作に関連するメソッドやプロパティを提供します。モデルはアプリケーションのロジックやビューに関連する機能を持ち、データの整形やバリデーション、操作の実行などを行います。
要約すると、エンティティはデータベースのテーブルやコレクションに対応し、データベースの永続化やデータの取得を扱います。一方、モデルはアプリケーションのデータの構造や振る舞いを表現し、アプリケーションのロジックやビューに関連する操作を提供します。モデルは通常、エンティティからのデータの変換や加工を担当しますが、エンティティとモデルの具体的な役割や関係はプロジェクトやアーキテクチャによって異なる場合もあります。
シリアライザーとビルダーの違い
シリアライザーとビルダーは、APIレスポンスを組み立てるための異なるアプローチ
シリアライザー(Serializer)は、モデルの属性や関連データをシリアライズ(直列化)して、APIレスポンスのデータ構造やフォーマットを定義します。
シリアライザーは、モデルの特定の属性を選択したり、関連データを含めたり、カスタムフィールドを追加したりすることが可能。
シリアライザーを使用することで、モデルのデータをAPIレスポンスとしてクライアントに提供する際の表現方法を制御できます。
一方、ビルダー(Builder)は、レスポンスの実際のデータ構造を組み立てるためのツールやクラスを指します。ビルダーは、シリアライザーが指示したデータの形式や構造にしたがって、最終的なAPIレスポンスのデータを組み立てます。ビルダーは通常、データの追加や削除、ネスト、整形などの操作を行います。
つまり、シリアライザーはAPIレスポンスの形式を定義し、ビルダーはその定義に基づいて実際のデータを組み立てる役割を担っています。シリアライザーは抽象的な概念であり、ビルダーは具体的な操作を行うための具現化です。
Solidとデザインパターンの違い
SOLID原則とデザインパターンは、ともにソフトウェア設計において良い設計をするための原則やパターンですが、目的や対象が異なります。
SOLID原則
SOLID原則は、オブジェクト指向プログラムの設計原則の集まりで、以下の5つの原則から成り立っています。
-
S: Single Responsibility Principle (単一責任の原則)
- ひとつのクラスは、ひとつの責任だけを持つべきです。
-
O: Open/Closed Principle (開放閉鎖の原則)
- ソフトウェアのエンティティ(クラス、モジュール、関数など)は、拡張に対しては開かれていて、修正に対しては閉じているべきです。
-
L: Liskov Substitution Principle (リスコフの置換原則)
- サブタイプは、そのスーパータイプと置換可能であるべきです。
-
I: Interface Segregation Principle (インターフェース分離の原則)
- クライアントは、不必要なインターフェースに依存するべきではありません。
-
D: Dependency Inversion Principle (依存関係逆転の原則)
- 高レベルのモジュールは、低レベルのモジュールに依存すべきではなく、抽象に依存すべきです。
SOLID原則は、コードの可読性や保守性、拡張性を向上させるための基本的なガイドラインとなります。
デザインパターン
デザインパターンは、特定の問題を解決するための一般的な設計のテンプレートやパターンです。再利用可能な設計のソリューションであり、ソフトウェア開発において一般的に遭遇する設計上の問題に対するベストプラクティスです。
代表的なデザインパターンには、以下のようなものがあります。
-
Creational Patterns (生成パターン)
- オブジェクトの生成方法を定義します。例:Singleton、Factory Method、Abstract Factory、Builder、Prototype。
-
Structural Patterns (構造パターン)
- クラスやオブジェクトの組み合わせ方を定義します。例:Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy。
-
Behavioral Patterns (振る舞いパターン)
- オブジェクト間の協力や責任の分担の仕方を定義します。例:Chain of Responsibility、Command、Interpreter、Iterator、Mediator、Memento、Observer、State、Strategy、Template Method、Visitor。
まとめ
- SOLID原則は、オブジェクト指向設計の基本的な原則であり、クラス設計のガイドラインを提供します。
- デザインパターンは、特定の設計上の問題を解決するための再利用可能なソリューションです。
これらは互いに補完関係にあり、SOLID原則を守ることでデザインパターンが適切に適用されやすくなり、デザインパターンを利用することでSOLID原則に従った設計が容易になります。
クリーンアーキテクチャ(Clean Architecture)とデザインパターン(Design Patterns)は、ソフトウェア設計とアーキテクチャの異なる側面を表す概念ですが、異なるアプローチと焦点を持っています。以下は、それぞれの概念の主な違いです:
-
クリーンアーキテクチャ(Clean Architecture):
- クリーンアーキテクチャは、ソフトウェアのアーキテクチャに焦点を当てた設計アプローチです。アプリケーション全体の構造とコンポーネント間の関係について考えます。
- クリーンアーキテクチャは、アプリケーションを複数の層に分割し、各層が特定の役割と責任を持つように設計します。これらの層には、エンティティ、ユースケース、インターフェースアダプタ(プレゼンター、コントローラなど)などが含まれます。
- クリーンアーキテクチャは、ソフトウェアの疎結合性、テスタビリティ、保守性などの品質属性を最適化しようとするアーキテクチャパターンです。
-
デザインパターン(Design Patterns):
- デザインパターンは、ソフトウェアの設計において、特定の問題を解決するための再利用可能なテンプレートやアイデアです。デザインパターンは、特定の問題に対処するためにテストされたアーキテクチャや構造を提供します。
- デザインパターンは、ソフトウェアのコード内で特定のプロブレムステートメントに対して適用できる汎用的なソリューションです。代表的なデザインパターンには、シングルトン、ファクトリ、ストラテジ、オブザーバ、デコレータなどがあります。
- デザインパターンは、特定のプログラミング言語やテクノロジに依存せず、プログラムの品質と保守性を向上させるために広く使用されています。
要するに、クリーンアーキテクチャはアプリケーション全体の設計とアーキテクチャに焦点を当て、コンポーネント間の関係を強調します。一方、デザインパターンは、個々のコードのレベルで再利用可能なソリューションを提供し、ソフトウェアデザインの小さな側面に焦点を当てます。デザインパターンは、クリーンアーキテクチャの一部として使用されることがありますが、それ自体がソフトウェアの全体的なアーキテクチャを規定するものではありません。
配列
破壊的な配列操作と非破壊的な配列操作があることを忘れてはいけない。 破壊的なメソッドがそのプログラムにないときは、一度コピーなどをして退避する対応などをする。
switch
switchはbreakだけではなくreturnでも良い。 falseやtrueが返す値が一致していた場合はわざとbreakを抜かすのもあり
switch (a) {
case "b":
false;
break;
case "c":
false;
break;
case "d":
false;
break;
default:
return;
}
// これを以下に変更できる。
switch (a) {
case "b":
case "c":
case "d":
false;
break;
default:
return;
}
リフレクション
リフレクション(Reflection)とは、プログラムが実行時に自分自身の構造や振る舞いを調べたり操作したりできる仕組みのことを指す。 これにより、ソースコードを書いている時点で特定のクラスやオブジェクトのプロパティやメソッドを知らなくても、実行時にその情報を動的に取得できる。
簡単に言うと、リフレクションを使うと次のようなことが可能になる
- オブジェクトがどんなメソッドやプロパティを持っているかを実行時に調べる。
- プロパティやメソッドにアクセスしたり、値を変更したりできる。
- あるクラスのインスタンスを動的に生成したり、メソッドを動的に呼び出す。
例:TypeScriptにおけるリフレクションの使用例
以下はTypeScriptでリフレクションを使ってオブジェクトのプロパティ名と値を動的に取得する例です。
class User {
id: string;
name: string;
email: string;
constructor(id: string, name: string, email: string) {
this.id = id;
this.name = name;
this.email = email;
}
}
const user = new User('1', 'name', '<name@example.com>');
// リフレクションを使ってプロパティ名と値を取得
Object.keys(user).forEach(key => {
console.log(`Property: ${key}, Value: ${user[key as keyof User]}`);
});
Property: id, Value: 1
Property: name, Value: name
Property: email, Value: <name@example.com>
この例では、Object.keys() を使ってオブジェクトのプロパティ名を動的に取得しています。そして、そのプロパティの値にアクセスしています。これがリフレクションの基本的な使用方法です。
リフレクションの用途
リフレクションは以下のような場合に便利。
- ライブラリやフレームワークの内部実装 例えば、ORM(オブジェクトリレーショナルマッピング)では、データベースのフィールドにマッピングするために、クラスのプロパティを動的に解析することがよくあります。
- デバッグやロギング どのようなプロパティやメソッドが含まれているかを調べたり、その値を取得して表示したりできます。
- 柔軟性の高いコードの実装 事前にクラスやオブジェクトの構造が分からない場合でも、動的にそのクラスを扱うことができるので、汎用的な処理を実現できます。
メリットとデメリット。
- メリット 動的にオブジェクトの状態や構造を調べることで、柔軟で再利用可能なコードを実現できる 事前に知らない型やオブジェクトを扱うことができるため、汎用的なライブラリやツールの開発に役立つ。
- デメリット リフレクションは通常のコードに比べて実行時のコスト(パフォーマンスへの影響)が高くなる。 動的に型を扱うので、コンパイル時にエラーが検出されにくくなる。
JavaScriptで書く論理回路まとめ(条件分 & 関数)
AND(論理積)
| A | B | A && B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
if (a && b) {
// 両方 true のとき
}
function and(a, b) {
return a && b;
}
OR(論理和)
| A | B | A || B | |---|---|--------| | 0 | 0 | 0 | | 0 | 1 | 1 | | 1 | 1 | 1 |
if (a || b) {
// どちらか true のとき
}
function or(a, b) {
return a || b;
}
NOT(否定)
| A | !A |
|---|---|
| 0 | 1 |
| 1 | 0 |
if (!a) {
// a が false のとき
}
function not(a) {
return !a;
}
XOR(排他的論理和)
| A | B | A ⊕ B |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
if ((a && !b) || (!a && b)) {
// どちらか一方だけ true のとき
}
// ビット演算として
if (a ^ b) {
// 数値として XOR を使う場合(0 or 1で)
}
function xor(a, b) {
return (a && !b) || (!a && b);
}
// もっとシンプルに書く方法
if (a !== b) {
// どちらか一方だけ true のとき
}
NAND(否定論理積)
| A | B | !(A && B) |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
if (!(a && b)) {
// AND の逆(1つでも false なら true)
}
function nand(a, b) {
return !(a && b);
}
NOR(否定論理和)
| A | B | !(A || B) | |—|—|———–| | 0 | 0 | 1 | | 0 | 1 | 0 | | 1 | 0 | 0 | | 1 | 1 | 0 |
if (!(a || b)) {
// OR の逆(両方 false のとき)
}
function nor(a, b) {
return !(a || b);
}
XNOR(排他的論理和の否定)
| A | B | !(A ⊕ B) |
|---|---|---|
| 0 | 0 | 1 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
if ((a && b) || (!a && !b)) {
// a と b が同じとき
}
// もっと簡単な書き方
if (a === b) {
// XNOR: aとbが同じとき
}
function xnor(a, b) {
return (a && b) || (!a && !b);
}