読み込み可能なワークコード


いくつかのコードのバランスを読み、まだ動作可能です.
今日、私はコーディングして、いくつかの古いコードをリファクタにすることに決めました.具体的には、このコードはF - Chernの寓話Elmishアプリでナビゲーション更新を処理しています.
let routeToPage routeOpt =
    match routeOpt with
    | None ->
        let page, effects = OpsUser.Search.init None
        OpsUserSearch page, effects
    | Some route ->
        match route with
        | ToOpsUserSearch searchOpt ->
            let page, effects = OpsUser.Search.init searchOpt
            OpsUserSearch page, effects
        | ToOpsUserAdd ->
            let page, effects = OpsUser.Add.init ()
            OpsUserAdd page, effects
この関数は多くのルートケースがありますが、ここでは2つだけ示します.

今すぐリファクタリング
最初に重複を取り除きました.最も内側の複製で始まるpage, effect を繰り返します.この重複をヘルパー関数で削除できます.
module Tuple =
    let mapFirst f (first, second) =
        f first, second

let routeToPage routeOpt =
    match routeOpt with
    | None ->
        OpsUser.Search.init None
        |> Tuple.mapFirst OpsUserSearch
    | Some route ->
        match route with
        | ToOpsUserSearch searchOpt ->
            OpsUser.Search.init searchOpt
            |> Tuple.mapFirst OpsUserSearch
        | ToOpsUserAdd ->
            OpsUser.Add.init ()
            |> Tuple.mapFirst OpsUserAdd
The mapFirst ヘルパー関数はこのコードに特有ではありません.これは任意のタプルで使用することができます.それで、必要に応じて後で抽出できる小さなタプルモジュールを作りました.
次に、これらのすべてのケースは同じことをしますが、別のページタグ、init関数、init引数を使用します.それで、我々はそれらをパラメータ化するヘルパーを作ることができます.
module Tuple =
    let mapFirst f (first, second) =
        f first, second

let routeToPage routeOpt =
    let inline initPage pageTag init initArg =
        init initArg
        |> Tuple.mapFirst pageTag
    match routeOpt with
    | None ->
        initPage OpsUserSearch OpsUser.Search.init None
    | Some route ->
        match route with
        | ToOpsUserSearch searchOpt ->
            initPage OpsUserSearch OpsUser.Search.init searchOpt
        | ToOpsUserAdd ->
            initPage OpsUserAdd OpsUser.Add.init ()

I used inline here as micro optimization. You can omit/ignore that as it won't make any logical difference to the code. Generally it is best to avoid using it in other places unless you know how it will affect execution.


それで、ケースは1つのライナーにあります.また、メインのケースをデフォルトの1つから別の関数に分割できます.また、その関数を再利用してデフォルトのケースを初期化します.
module Tuple =
    let mapFirst f (first, second) =
        f first, second

let initRoute route =
    let inline initPage pageTag init initArg =
        init initArg
        |> Tuple.mapFirst pageTag
    match route with
    | ToOpsUserSearch searchOpt ->
        initPage OpsUserSearch OpsUser.Search.init searchOpt
    | ToOpsUserAdd ->
        initPage OpsUserAdd OpsUser.Add.init ()

let routeToPage routeOpt =
    match routeOpt with
    | None ->
        initRoute (ToOpsUserSearch None)
    | Some route ->
        initRoute route
ヒアinitRoute DEVSが前進するように変更する主要な領域になります.また、オプション機能を見ることができますrouteToPage .
module Tuple =
    let mapFirst f (first, second) =
        f first, second

let initRoute route =
    let inline initPage pageTag init initArg =
        init initArg
        |> Tuple.mapFirst pageTag
    match route with
    | ToOpsUserSearch searchOpt ->
        initPage OpsUserSearch OpsUser.Search.init searchOpt
    | ToOpsUserAdd ->
        initPage OpsUserAdd OpsUser.Add.init ()

let routeToPage routeOpt =
    routeOpt
    |> Option.defaultValue (ToOpsUserSearch None)
    |> initRoute
脂肪のすべてのオンスを削除するには、無料のスタイルを使用することができます.これは抽出を必要とするinitPage 外部initRoute . したがって、私は削除しますinline それで、後で誰かがそれを再利用しようとするならば、彼らは予想外のパフォーマンス問題を得ません.デフォルトルートを独自の値として分離します.これは、中で唯一のものを抽出しますrouteToPage それは時間とともに変化するでしょう.
module Tuple =
    let mapFirst f (first, second) =
        f first, second

let initPage pageTag init initArg =
    init initArg
    |> Tuple.mapFirst pageTag

let initRoute = function
    | ToOpsUserSearch searchOpt ->
        initPage OpsUserSearch OpsUser.Search.init searchOpt
    | ToOpsUserAdd ->
        initPage OpsUserAdd OpsUser.Add.init ()

let defaultRoute =
    ToOpsUserSearch None

let routeToPage =
    Option.defaultValue defaultRoute
    >> initRoute

これは良いですか.
それで、この時点で私は見つけることができるすべての重複を削除しました.今では大きな画像を見て時間です.どのようにクリアこのコードですか?あなたの間の経験は、それが全く明らかであると言うかもしれません.しかし、もしあなたがコーディングに新しいか?どのように多くの種類の構文をマスターする必要がありますか?どのように多くの層を理解するためにdevのトレースをする必要がありますrouteToPage ? 新しいDEVSが理解するのが特に難しいどんな構文もありますか?
私は、新しいdevの視点から読みやすくすることが好きです.これは、コードベースは、将来の私を含むすべての読者に理解できるようになります.そして、実用的に、それはより多くの柔軟性を許します.私は、特定のバックグラウンドで経験豊富なDEVSまたはDEVSを雇わなければなりません.すべての経験レベルと背景のDEVSは、より少ない時間でプロジェクトの間で移行することができます.
この観点から、コードは私が一般的な読みやすさを害すると思う多くの面を持っています.ここで私はおそらくコミットされます.
let initRoute route =
    let inline initPage pageTag init initArg =
        let page, effects = init initArg
        pageTag page, effects
    match route with
    | ToOpsUserSearch searchOpt ->
        initPage OpsUserSearch OpsUser.Search.init searchOpt
    | ToOpsUserAdd ->
        initPage OpsUserAdd OpsUser.Add.init ()

let defaultRoute =
    ToOpsUserSearch None

let routeToPage routeOpt =
    let route = routeOpt |> Option.defaultValue defaultRoute
    initRoute route
読みやすさに1つの課題は、無料の表記法です.それのような多くの機能プログラマ.しかし、一見して読むことは明白ではない.ポイントフリー機能は値割り当てのように見えます.あなたは、コード・ブロックの中に、ポイント・フリーである特定のサインのために見なければなりませんfunction or >> . それから、暗黙のパラメタは、何が実際に起こっているかについて、新しいプログラマーの心に疑いの余地を残すことができます.すべての点で、私はポイントフリーは抽象化よりも最適化のより多くであると考えます.そして、それが離れて最適化する複製のためにここで十分な値を加えません.
次に考えたTuple.mapFirst . 一箇所でのみ使用.それはそれを持っていないよりも多くのコードをもたらします.最悪のことにはinitPage 読みにくい.あなたが掘るときmapFirst , あなたがタプルの力学にコンテキストスイッチをする必要があります、あなたが理解しようとしていた問題から離れて.このような理由で、関数がベースFの残りの部分に含まれている場合でも、私は明快さのためにここでそれを使用しないだろう.
私は完全に値を確信していないinitPage , しかし、私は今それを保ちます.それは読みやすい.DEVSが最も一般的に働く場所で、それは少しコードを保存します.そして、それを理解することは1つのレベルの深い旅です.
書くことができたrouteToPage すべてのパイプで.
let routeToPage routeOpt =
    routeOpt
    |> Option.defaultValue defaultRoute
    |> initRoute
しかし、私がそれをコード化した方法がより明確であると思います.具体的には、最初の行は、オプションのルートをオプションでないオプションに変換します.それで、たとえdevが彼らが遭遇しなかったほど新しいものであってもOption.defaultValue , この関数はまだ表面レベルで理解できます.
率直に言って、このプロセスの最終結果はオリジナルより読みやすいようではありません.これは複製を意味していても、説明の価値について話す.しかし、結果はコードを特定の関数に変える可能性が低くなります.そしてそれはそこで再利用するためのツールを提供します.

閉鎖思考
良いコードは良い文学のようです:それはあなたの心の中に具体的な画像を形成する.しかし、それは良いワークベンチのようです.これらの目標を達成することができます-それは、単一の戦術があったならば、それは良いです-あなた自身の原則を繰り返さないでください.しかし、私はまだそれを見つけていません.代わりに良いコードを別のものを試してみて何を動作評価する必要があります.
私はこのコードの均衡について考えを共有した.どのようにコードのバランスをとるのですか?