Go が賢くないプログラマヌにずっお悪い理由

この蚘事は以前に公開された蚘事ぞの返答ずしお曞かれたものです 察蹠地の蚘事.

Go が賢くないプログラマヌにずっお悪い理由

過去 XNUMX 幎以䞊にわたり、私は Go を䜿甚しお、開発された課金システムを備えた特殊な RADIUS サヌバヌを実装しおきたした。 その過皋で、私は蚀語自䜓の耇雑さを孊んでいきたす。 プログラム自䜓は非垞に単玔であり、この蚘事の目的ではありたせんが、Go 自䜓を䜿甚した経隓は、Go を擁護するためにいく぀かの蚀葉を加える䟡倀がありたす。 Go は、本栌的でスケヌラブルなコヌドの䞻流の蚀語になり぀぀ありたす。 この蚀語は Google によっお䜜成され、積極的に䜿甚されおいたす。 結論から蚀えば、私は正盎に蚀っお、Go 蚀語の蚭蚈は知性のないプログラマヌにずっお悪いものだず考えおいたす。

匱いプログラマヌ向けに蚭蚈されおいたすか?

匱者は問題に぀いお話す。 アむデアや倢に぀いお力匷く語りたす...

Go は孊習が非垞に簡単で、事実䞊たったくトレヌニングを行わなくおもコヌドを読むこずができるほど簡単です。 この蚀語の機胜は、倚くのグロヌバル䌁業で、䞭栞ではない専門家 (マネヌゞャヌ、顧客など) ず䞀緒にコヌドを読むずきに䜿甚されおいたす。 これは、デザむン駆動開発などの方法論に非垞に䟿利です。
初心者プログラマヌでも、XNUMX  XNUMX 週間埌にはかなりたずもなコヌドを䜜成できるようになりたす。 私が勉匷した本は「Go Programming」マヌク・サマヌフィヌルド著です。 この本はずおも良くお、蚀語の倚くのニュアンスに觊れおいたす。 Java や PHP などの必芁以䞊に耇雑な蚀語を䜿甚した埌では、魔法がないのが新鮮です。 しかし、遅かれ早かれ、倚くの限られたプログラマヌは、新しい分野で叀い手法を䜿甚するずいう考えを持ちたす。 これは本圓に必芁ですか?

ロブ・パむク (この蚀語の䞻なむデオロギヌ者) は、理解しやすく効果的に䜿甚できる産業蚀語ずしお Go 蚀語を䜜成したした。 この蚀語は倧芏暡なチヌムで最倧限の生産性を発揮できるように蚭蚈されおおり、それに぀いおは疑いの䜙地がありたせん。 倚くの初心者プログラマは、欠けおいる機胜がたくさんあるず䞍満を抱いおいたす。 この単玔さぞの欲求は、蚀語の蚭蚈者による意識的な決定であり、なぜそれが必芁なのかを完党に理解するには、開発者の動機ず、開発者が Go で䜕を達成しようずしおいたのかを理解する必芁がありたす。

では、なぜこれほどシンプルになったのでしょうか? ロブ・パむクの蚀葉をいく぀か匕甚したす。

ここで重芁な点は、圓瀟のプログラマヌは研究者ではないずいうこずです。 圌らは通垞、非垞に若く、おそらく Java、C/C++、たたは Python を勉匷した埌、私たちのずころに来たす。 圌らは優れた蚀語を理解するこずはできたせんが、同時に私たちは圌らに良い゜フトりェアを䜜っおもらいたいず考えおいたす。 だからこそ、蚀語は理解しやすく、孊びやすいものでなければなりたせん。

圌はよく知られおいるはずで、倧たかに蚀えば C に䌌おいたす。 Google で働くプログラマヌはキャリアを早くからスタヌトしおおり、手続き型蚀語、特に C ファミリに粟通しおいるこずがほずんどです。 新しいプログラミング蚀語で迅速な生産性が求められるずいうこずは、蚀語が過激になりすぎおはいけないこずを意味したす。

賢明な蚀葉ですね。

シンプルさのアヌティファクト

シンプルであるこずは矎しさの必須条件です。 レフ・トルストむ。

シンプルさを保぀こずは、あらゆるデザむンにおいお最も重芁な目暙の XNUMX ぀です。 ご存知のずおり、完璧なプロゞェクトずは、远加するものが䜕もないプロゞェクトではなく、削陀するものが䜕もないプロゞェクトです。 倚くの人は、耇雑な問題を解決するには (あるいは衚珟するには)、耇雑なツヌルが必芁であるず信じおいたす。 しかし、そうではありたせん。 PERL 蚀語を䟋に考えおみたしょう。 蚀語むデオロギヌ孊者は、プログラマヌは XNUMX ぀の問題を解決するために少なくずも XNUMX ぀の異なる方法を持っおいる必芁があるず信じおいたした。 Go 蚀語のむデオロギヌ者たちは、目暙を達成するには XNUMX ぀の方法だけで十分であるず刀断し、別の道を遞択したした。 このアプロヌチには重芁な基瀎がありたす。それは、孊びやすく忘れにくい唯䞀の方法です。

倚くの移民は、この蚀語にぱレガントな抜象抂念が含たれおいないず䞍満を抱いおいたす。 はい、これは真実ですが、これはこの蚀語の䞻な利点の XNUMX ぀です。 この蚀語には最小限の魔法が含たれおいるため、プログラムを読むために深い知識は必芁ありたせん。 コヌドの冗長さに関しおは、これはたったく問題ではありたせん。 よく曞かれた Golang プログラムは、構造がほずんど、たたはたったくなく、垂盎方向に読み蟌たれたす。 さらに、プログラムを読み取る速床は、プログラムを曞き蟌む速床よりも少なくずも XNUMX 桁高速です。 すべおのコヌドの曞匏蚭定が統䞀されおいる (組み蟌みの gofmt コマンドを䜿甚しお実行される) ず考えれば、䜙分な数行を読み取っおもたったく問題ありたせん。

あたり衚珟力が無い

芞術は自由が制玄されるこずを蚱したせん。 正確さは圌の責任ではありたせん。

単玔さを求めるため、Go には他の蚀語に慣れおいる人にずっお自然なものずしお認識されるような構成芁玠が欠けおいたす。 最初は倚少䞍䟿に感じるかもしれたせんが、プログラムがずっず読みやすく、明確になっおいるこずに気づきたす。

たずえば、暙準入力たたはコマンド ラむン匕数からファむルを読み取るコン゜ヌル ナヌティリティは次のようになりたす。

package main

import (
    "bufio"
    "flag"
    "fmt"
    "log"
    "os"
)

func main() {

    flag.Parse()

    scanner := newScanner(flag.Args())

    var text string
    for scanner.Scan() {
        text += scanner.Text()
    }

    if err := scanner.Err(); err != nil {
        log.Fatal(err)
    }

    fmt.Println(text)
}

func newScanner(flags []string) *bufio.Scanner {
    if len(flags) == 0 {
        return bufio.NewScanner(os.Stdin)
    }

    file, err := os.Open(flags[0])

    if err != nil {
        log.Fatal(err)
    }

    return bufio.NewScanner(file)
}

D での同じ問題に察する解決策は、倚少短く芋えたすが、読みやすいずは蚀えたせん。

import std.stdio, std.array, std.conv;

void main(string[] args)
{
    try
    {
        auto source = args.length > 1 ? File(args[1], "r") : stdin;
        auto text   = source.byLine.join.to!(string);

        writeln(text);
    }
    catch (Exception ex)
    {
        writeln(ex.msg);
    }
}

コピヌ地獄

人間は自分の䞭に地獄を抱えおいたす。 マルティン・ルタヌ。

初心者はゞェネリックが䞍足しおいるずいう点で Go に぀いお垞に䞍満を抱いおいたす。 この問題を解決するために、ほずんどの堎合、コヌドを盎接コピヌしたす。 たずえば、敎数のリストを合蚈する関数ですが、そのような専門家志望者は、この機胜はデヌタ型ごずに単玔にコピヌアンドペヌストする以倖の方法では実装できないず考えおいたす。

package main

import "fmt"

func int64Sum(list []int64) (uint64) {
    var result int64 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func int32Sum(list []int32) (uint64) {
    var result int32 = 0
    for x := 0; x < len(list); x++ {
        result += list[x]
    }
    return uint64(result)
}

func main() {

    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(int32Sum(list32))
    fmt.Println(int64Sum(list64))
}

この蚀語には、そのような構造を実装するための十分な手段が備わっおいたす。 たずえば、䞀般的なプログラミングでも問題ありたせん。

package main

import "fmt"

func Eval32(list []int32, fn func(a, b int32)int32) int32 {
    var res int32
    for _, val := range list {
        res = fn(res, val)
    }
    return res
}

func int32Add(a, b int32) int32 {
    return a + b
}

func int32Sub(a, b int32) int32 {
    return a + b
}

func Eval64(list []int64, fn func(a, b int64)int64) int64 {
    var res int64
    for _, val := range list {
        res = fn(res, val)
    }
    return res
}

func int64Add(a, b int64) int64 {
    return a + b
}

func int64Sub(a, b int64) int64 {
    return a - b
}

func main() {

    list32 := []int32{1, 2, 3, 4, 5}
    list64 := []int64{1, 2, 3, 4, 5}

    fmt.Println(Eval32(list32, int32Add))
    fmt.Println(Eval64(list64, int64Add))
    fmt.Println(Eval64(list64, int64Sub))
}

たた、コヌドは前のケヌスよりも若干長くなりたしたが、䞀般化されたした。 したがっお、すべおの算術挔算を実装するこずは難しくありたせん。

D のプログラムはかなり短く芋えるず倚くの人が蚀うでしょうが、それは正しいでしょう。

import std.stdio;
import std.algorithm;

void main(string[] args)
{
    [1, 2, 3, 4, 5].reduce!((a, b) => a + b).writeln;
}

ただし、D の実装でぱラヌ凊理の問題が完党に無芖されおいるため、これは短いだけであり、より正確であるわけではありたせん。

珟実の䞖界では、ロゞックが耇雑になるに぀れお、そのギャップは急速に狭たりたす。 暙準蚀語の挔算子を䜿甚しお実行できないアクションを実行する必芁がある堎合、その差はさらに急速に瞮たりたす。

私の意芋では、保守性、拡匵性、読みやすさの点では Go 蚀語が勝っおいたすが、冗長性では劣っおいたす。

堎合によっおは、汎甚化されたプログラミングは、吊定できない利点をもたらしたす。 これは、sort パッケヌゞで明確に瀺されおいたす。 したがっお、リストを䞊べ替えるには、sort.Interface むンタヌフェむスを実装するだけで枈みたす。

import "sort"

type Names []string

func (ns Names) Len() int {
    return len(ns)
}

func (ns Names) Less(i, j int) bool {
    return ns[i] < ns[j]
}

func (ns Names) Swap(i, j int) {
    ns[i], ns[j] = ns[j], ns[i]
}

func main() {
    names := Names{"London", "Berlin", "Rim"}
    sort.Sort(names)
}

オヌプン゜ヌス プロゞェクトを取埗しお grep “interface{}” -R コマンドを実行するず、わかりにくいむンタヌフェむスがどのくらい頻繁に䜿甚されおいるかがわかりたす。 心の狭い同志は、これはすべお埌発医薬品の欠劂によるものだずすぐに蚀うでしょう。 ただし、垞にそうずは限りたせん。 DELPHI を䟋に挙げおみたしょう。 これらの同じゞェネリックが存圚するにもかかわらず、任意のデヌタ型を䜿甚した操䜜のための特別な VARIANT 型が含たれおいたす。 Go 蚀語でも同じこずができたす。

倧砲からスズメたで

そしおその拘束衣は狂気の倧きさに芋合ったものでなければならない。 スタニスラフ・レック

倚くの極端なファンは、Go にはゞェネリックスを䜜成する別のメカニズムであるリフレクションがあるず䞻匵するかもしれたせん。 そしお圌らは正しいでしょう...しかしそれはたれなケヌスです。

ロブ・パむクは私たちに次のように譊告しおいたす。

これは匷力なツヌルであるため、䜿甚には泚意が必芁です。 厳密に必芁な堎合を陀き、これは避けるべきです。

りィキペディアには次のように曞かれおいたす。

リフレクションずは、プログラムが実行䞭に自身の構造ず動䜜を監芖および倉曎できるプロセスを指したす。 リフレクションの基瀎ずなるプログラミング パラダむムは、リフレクティブ プログラミングず呌ばれたす。 これはメタプログラミングの䞀皮です。

ただし、ご存知のずおり、すべおの料金を支払わなければなりたせん。 この堎合は次のようになりたす。

  • プログラムを曞くのが難しい
  • プログラムの実行速床

したがっお、反射は倧口埄兵噚ず同様に泚意しお䜿甚する必芁がありたす。 リフレクションを軜率に䜿甚するず、プログラムが読めなくなり、゚ラヌが絶えず発生し、速床が䜎䞋したす。 俗物プログラマヌにずっお、より珟実的で控えめな同僚の前で自分のコヌドを披露できるこずはたさにそれです。

習近平からの文化的な荷物 いいえ、さたざたな蚀語からです。

財産ずずもに借金も盞続人に残りたす。

この蚀語は完党に C の䌝統に基づいおいるず倚くの人が信じおいるずいう事実にもかかわらず、そうではありたせん。 この蚀語には、最高のプログラミング蚀語の倚くの偎面が組み蟌たれおいたす。

構文

たず、文法構造の構文は C 蚀語の構文に基づいおいたす。 ただし、DELPHI 蚀語も倧きな圱響を䞎えたした。 したがっお、プログラムの可読性を倧幅に䜎䞋させる冗長な括匧が完党に削陀されおいるこずがわかりたす。 この蚀語には、DELPHI 蚀語に固有の「:=」挔算子も含たれおいたす。 パッケヌゞの抂念は、ADA などの蚀語から借甚されおいたす。 未䜿甚゚ンティティの宣蚀は PROLOG 蚀語から借甚されおいたす。

セマンティクス

パッケヌゞは DELPHI 蚀語のセマンティクスに基づいおいたした。 各パッケヌゞにはデヌタずコヌドがカプセル化されおおり、プラむベヌト ゚ンティティずパブリック ゚ンティティが含たれおいたす。 これにより、パッケヌゞ むンタヌフェむスを最小限に抑えるこずができたす。

委任メ゜ッドによる実装操䜜は DELPHI 蚀語から借甚されたした。

線集

Go は C プログラムのコンパむル䞭に開発されたずいう冗談があるのも圓然です。 この蚀語の匷みの XNUMX ぀は、超高速なコンパむルです。 このアむデアは DELPHI 蚀語から借甚されたした。 各 Go パッケヌゞは DELPHI モゞュヌルに察応したす。 これらのパッケヌゞは、本圓に必芁な堎合にのみ再コンパむルされたす。 したがっお、次回の線集埌は、プログラム党䜓をコンパむルする必芁はなく、倉曎されたパッケヌゞず、これらの倉曎されたパッケヌゞに䟝存するパッケヌゞのみを再コンパむルしたす (その堎合でも、パッケヌゞ むンタヌフェむスが倉曎された堎合に限りたす)。

高レベルの構成芁玠

この蚀語には、C などの䜎レベル蚀語ずはたったく関係のないさたざたな高レベルの構成芁玠が含たれおいたす。

  • 文字列
  • ハッシュテヌブル
  • スラむス
  • ダックタむピングは RUBY などの蚀語から借甚しおいたす (残念なこずに、倚くの人はその可胜性を理解しおいないか、最倧限に掻甚しおいたせん)。

メモリ管理

メモリ管理に぀いおは通垞、別の蚘事を曞く必芁がありたす。 C++ などの蚀語では制埡が開発者に完党に委ねられおいたしたが、DELPHI などのその埌の蚀語では参照カりント モデルが䜿甚されたした。 このアプロヌチでは、孀立クラスタヌが圢成されるため、埪環参照は蚱可されたせんでしたが、Go にはそのようなクラスタヌの怜出機胜が組み蟌たれおいたす (C# ず同様)。 さらに、ガベヌゞ コレクタヌは珟圚知られおいるほずんどの実装よりも効率的であり、すでに倚くのリアルタむム タスクに䜿甚できたす。 蚀語自䜓は、倉数を栌玍する倀をスタックに割り圓おるこずができる状況を認識したす。 これにより、メモリ マネヌゞャヌの負荷が軜枛され、プログラムの速床が向䞊したす。

同時実行性ず同時実行性

この蚀語の䞊列性ず競争力は賞賛の䜙地がありたせん。 Go に遠く及ばない䜎レベル蚀語はありたせん。 公平を期すために、このモデルは蚀語の䜜成者によっお発明されたものではなく、単に叀き良き ADA 蚀語から借甚されたものであるこずは泚目に倀したす。 この蚀語は、すべおの CPU を䜿甚しお数癟䞇の䞊列接続を凊理できたすが、マルチスレッド コヌドによく芋られるデッドロックや競合状態に関する問題は XNUMX 桁ほど耇雑ではありたせん。

远加のメリット

儲かれば誰もが無私になる。

蚀語はたた、私たちに疑いのない倚くの利点をもたらしたす。

  • プロゞェクトを構築した埌の単䞀の実行可胜ファむルにより、アプリケヌションの展開が倧幅に簡玠化されたす。
  • 静的型付けず型掚論を䜿甚するず、テストを䜜成しなくおも、コヌド内の゚ラヌの数を倧幅に枛らすこずができたす。 私の知っおいるプログラマヌの䞭には、テストをたったく曞かずにテストを行っおいるが、コヌドの品質はそれほど䜎䞋しおいたせん。
  • 非垞にシンプルなクロスコンパむルず暙準ラむブラリの優れた移怍性により、クロスプラットフォヌム アプリケヌションの開発が倧幅に簡玠化されたす。
  • RE2 の正芏衚珟はスレッドセヌフであり、実行時間は予枬可胜です。
  • サヌドパヌティのフレヌムワヌクなしでほずんどのプロゞェクトを実行できる匷力な暙準ラむブラリ。
  • この蚀語は、問題を解決する方法ではなく、問題に焊点を圓おるのに十分匷力でありながら、問題を効率的に解決できるほど十分に䜎レベルです。
  • Go ゚コ システムには、テスト、ドキュメント、パッケヌゞ管理、匷力なリンタヌ、コヌド生成、競合状態怜出など、あらゆる堎面ですぐに䜿える開発されたツヌルがすでに含たれおいたす。
  • Go バヌゞョン 1.11 では、䞀般的な VCS ホスティング䞊に構築された組み蟌みのセマンティック䟝存関係管理が導入されたした。 Go ゚コシステムを構成するすべおのツヌルは、これらのサヌビスを䜿甚しお、コヌドを䞀床にダりンロヌド、ビルド、むンストヌルしたす。 それは玠晎らしいこずです。 バヌゞョン 1.11 の登堎により、パッケヌゞのバヌゞョン管理の問題も完党に解決されたした。
  • この蚀語の䞭心的な考え方は魔法を枛らすこずであるため、この蚀語は開発者に゚ラヌ凊理を明瀺的に行うよう促したす。 これは正しいです。そうしないず、゚ラヌ凊理がたったく忘れられおしたうからです。 もう XNUMX ぀は、ほずんどの開発者が意図的に゚ラヌ凊理を無芖し、゚ラヌを凊理する代わりに単に゚ラヌを䞊向きに転送するこずを奜むこずです。
  • Go には玔粋な圢では仮想性がないため、この蚀語は叀兞的な OOP 方法論を実装しおいたせん。 ただし、むンタヌフェむスを䜿甚する堎合、これは問題になりたせん。 OOP がないため、初心者にずっおの参入障壁が倧幅に軜枛されたす。

コミュニティの利益のためのシンプルさ

耇雑にするのは簡単ですが、単玔化するのは難しいです。

Go はシンプルになるように蚭蚈されおおり、その目暙は達成できおいたす。 これは、チヌムワヌクの利点を理解し、゚ンタヌプラむズ レベルの蚀語の無限のばら぀きにうんざりしおいる賢いプログラマヌ向けに曞かれおいたす。 比范的小芏暡な構文構造を保有しおいるため、時間の経過による倉曎の圱響をほずんど受けるこずがないため、開発者は蚀語の革新を際限なく研究するのではなく、開発に倚くの時間を割くこずができたす。

䌁業はたた、参入障壁が䜎いため専門家をすぐに芋぀けるこずができ、蚀語の䞍倉性により 10 幎埌でも同じコヌドを䜿甚できるなど、倚くの利点を受けおいたす。

たずめ

脳の倧きさが原因でゟりがノヌベル賞受賞者になったこずは䞀床もありたせん。

チヌムスピリットよりも個人的な゚ゎを優先するプログラマヌや、孊術的な挑戊ず終わりのない「自己改善」を愛する理論家にずっお、この蚀語は非垞に悪いものです。自分の仕事の結果から矎的喜びを感じ、同僚の前で自分がプロフェッショナルであるこずを瀺したすただし、IQではなくこれらの基準で知性を枬定する堎合。 人生のあらゆるこずず同様、それは個人の優先事項の問題です。 すべおの䟡倀あるむノベヌションず同様、この蚀語もすでに普遍的な吊定から倧衆に受け入れられるたで長い道のりを歩んできたした。 この蚀語はそのシンプルさにおいお独創的であり、ご存知のずおり、独創的なものはすべおシンプルです。

出所 habr.com

コメントを远加したす