30

私は、Groovy についてさらに調査し、実験を行っており、Java では実行できない/実行できないことを Groovy で実装することの長所と短所に頭を悩ませようとしています。私は静的で強く型付けされた言語に深く浸っているので、動的プログラミングはまだ概念にすぎません。

Groovy はダックタイプを実行できる機能を提供してくれますが、その価値はよくわかりません。ダックタイピングは静的タイピングよりも生産性が高いのはなぜですか? コードの利点を理解するために、コードの練習でどのようなことを行うことができますか?

Groovy を念頭に置いてこの質問をしますが、必ずしも Groovy の質問ではないことを理解しているので、すべてのコード キャンプからの回答を歓迎します。

4

10 に答える 10

20

ダックタイピングに関するコメントの多くは、その主張を実際に裏付けるものではありません。タイプについて「心配する必要がない」ということは、メンテナンスやアプリケーションの拡張に耐えられません。前回の契約で Grails が動作しているのを見る良い機会が本当にありました。実際に見ていてとても面白いです。「アプリを作成」して作業を開始できるようになったことについては、誰もが満足しています。

Groovy も同じように思えます。確かに、非常に簡潔なコードを書くことができますし、プロパティやコレクションなどを操作する方法には確かに便利な機能があります。ある時点で、なぜプロジェクトが 80% のテストと 20% の作業になったのか疑問に思ったことでしょう。ここでの教訓は、「小さく」しても「読みやすい」コードにはならないということです。申し訳ありませんが、その単純なロジック - 直感的に知る必要があるほど、そのコードを理解するプロセスはより複雑になります。GUI が長年にわたって過度に象徴的なものになることを控えてきたのはそのためです。

そのプロジェクトの人々は、学んだ教訓を「釘付けにする」のに苦労しているように見えましたが、T型の単一要素、Tの配列、ErrorResult、またはnullのいずれかを返すメソッドがある場合...かなり明白になります。

しかし、Groovy を使用することで得られたことが 1 つあります。

于 2010-01-18T23:10:38.667 に答える
11

ダックタイピングは、入力時にエラーを指摘できる最新の IDE の静的チェックのほとんどを無効にします。これを利点と考える人もいます。IDE/コンパイラーに、私が愚かなプログラマーのトリックを作ったことをできるだけ早く教えてもらいたいです。

ダックタイピングに対する私の最近のお気に入りの議論は、Grails プロジェクトの DTO からのものです。

class SimpleResults {
    def results
    def total
    def categories
}

whereresultsは のようなものMap<String, List<ComplexType>>であることがわかります。これは、作成された場所が見つかるまで、さまざまなクラスでのメソッド呼び出しの跡をたどることによってのみ発見できます。最終的な好奇心のために、totalは のサイズの合計であり、List<ComplexType>categoriesのサイズですMap

元の開発者には明らかだったかもしれませんが、貧弱なメンテナンス担当者 (ME) は、これを追跡するために多くの髪の毛を失いました。

于 2008-10-30T13:09:55.503 に答える
9

しばらく使ってみないと、ダックタイピングの価値を理解するのは少し難しいです。慣れてくると、インターフェースを扱う必要がないことや、何かが正確にどのような型であるかを気にする必要がないことが、どれだけの負担であるかがわかります。

于 2008-09-07T00:42:26.033 に答える
7

信じられないほどの静的型システムを持つ Haskell を使用している場合、静的型付けに問題はありません。ただし、Java や C++ など、型システムがひどく機能しなくなる言語を使用している場合は、ダック タイピングを使用すると間違いなく改善されます。

Java で「 map 」のような単純なものを使おうとしていると想像してみてください(データ構造のことではありません)。ジェネリックでさえサポートが不十分です。

于 2008-09-07T01:09:15.250 に答える
6

次に、EMACS と vi のどちらが優れていますか? これは進行中の宗教戦争の 1 つです。

このように考えてください: 言語が静的に型付けされている場合、正しいプログラムはすべて正しいでしょう。静的型付けが行うことは、実行時ではなくコンパイル時に型の不一致を検出するのに十分な情報をコンパイラーに持たせることです。これは、インクリメンタルな種類のプログラミングを行っている場合は煩わしい場合がありますが、(私は維持しています) プログラムについて明確に考えている場合は、それほど問題ではありません。一方、オペレーティング システムや電話交換機のように、数十、数百、数千人が作業している、または非常に高い信頼性を必要とする非常に大きなプログラムを構築している場合は、コンパイラに次のことを実行させることができます。適切なコード パスを実行するためのテスト ケースを必要とせずに、大規模なクラスの問題を検出します。

動的型付けが新しいものであるかのように言うわけではありません。たとえば C は、 afoo*を a にいつでもキャストできるため、効果的に動的に型付けされbar*ます。bar*アドレスが本当に を指しているときに、 に適切なコードを決して使用しないことが C プログラマーとしての私の責任であることを意味しますfoo*。しかし、大規模なプログラムの問題の結果として、C は lint(1) のようなツールを成長させ、その型システムを強化しtypedef、最終的に C++ で強く型付けされたバリアントを開発しました。(そしてもちろん、C++ は、さまざまなキャストとジェネリック/テンプレート、および RTTI を使用して、強力な型付けを回避する方法を開発しました。

ただし、もう 1 つ --- 「アジャイル プログラミング」と「動的言語」を混同しないでください。 アジャイル プログラミングとは、プロジェクトで人々が協力して作業する方法に関するものです。プロジェクトは、プログラマーにとって人道的な環境を維持しながら、変化する要件に適応して顧客のニーズを満たすことができるでしょうか? 動的に型付けされた言語 (Ruby、Smalltalk など) ではより生産性が高いため、動的型付け言語で行うことができますが、C やアセンブラーでも行うことができ、成功しています。実際、Rally Developmentはアジャイル手法 (特に SCRUM) を使用して、マーケティングと文書化を行っています。

于 2008-11-09T15:12:25.043 に答える
5

私見ですが、変数やメソッドに一貫した方法で名前を付けるなど、いくつかの規則に従うと、ダックタイピングの利点がさらに大きくなります。ケンGの例をとると、私はそれが最もよく読めると思います:

class SimpleResults {
    def mapOfListResults
    def total
    def categories
}

「calculateRating(A、B)」という名前の操作でコントラクトを定義するとします。ここで、AとBは別のコントラクトに準拠しています。擬似コードでは、次のようになります。

Long calculateRating(A someObj, B, otherObj) {

   //some fake algorithm here:
   if(someObj.doStuff('foo') > otherObj.doStuff('bar')) return someObj.calcRating());
   else return otherObj.calcRating();

}

これをJavaで実装する場合は、AとBの両方が次のようなインターフェイスを実装する必要があります。

public interface MyService {
    public int doStuff(String input);
}

さらに、評価を計算するための契約を一般化したい場合(たとえば、評価計算のための別のアルゴリズムがある場合)、インターフェイスも作成する必要があります。

public long calculateRating(MyService A, MyServiceB);

ダックタイピングを使用すると、インターフェイスを捨てて、ランタイムに依存するだけで、AとBの両方がdoStuff()呼び出しに正しく応答します。特定の契約定義は必要ありません。これはあなたのために働くことができますが、あなたに対しても働くことができます。

欠点は、他の人がコードを変更したときにコードが壊れないようにするために、特に注意する必要があることです(つまり、他の人はメソッド名と引数の暗黙のコントラクトを認識している必要があります)。

これは特にJavaで悪化することに注意してください。この場合、構文は(たとえばScalaと比較して)それほど簡潔ではありません。これの反例はLiftフレームワークであり、フレームワークのSLOCカウントはRailsに似ていると言われていますが、テスト内で型チェックを実装する必要がないため、テストコードの行数は少なくなっています。

于 2008-11-09T14:25:50.537 に答える
3

ダックタイピングが作業を節約する 1 つのシナリオを次に示します。

これは非常に簡単なクラスです

class BookFinder {
    def searchEngine

    def findBookByTitle(String title) {
         return searchEngine.find( [ "Title" : title ] ) 
    }
}

次に、単体テストを行います。

void bookFinderTest() {
    // with Expando we can 'fake' any object at runtime.
    // alternatively you could write a MockSearchEngine class.
    def mockSearchEngine = new Expando()
    mockSearchEngine.find = {
        return new Book("Heart of Darkness","Joseph Conrad")
    }

    def bf = new BookFinder()
    bf.searchEngine = mockSearchEngine
    def book = bf.findBookByTitle("Heart of Darkness")
    assert(book.author == "Joseph Conrad"
}

静的な型チェックがないため、SearchEngine を Expando に置き換えることができました。静的型チェックでは、SearchEngine がインターフェース、または少なくとも抽象クラスであることを確認し、その完全なモック実装を作成する必要がありました。これは手間がかかりますが、洗練された単一目的のモック フレームワークを使用することもできます。しかし、ダックタイピングは汎用的であり、私たちを助けてくれました.

ダックタイピングにより、呼び出されるメソッドを実装している限り、単体テストは依存関係の代わりに古いオブジェクトを提供できます。

強調しておくと、インターフェイスとクラス階層を注意深く使用すれば、静的に型付けされた言語でこれを行うことができます。しかし、ダックタイピングを使えば、より少ない思考とより少ないキーストロークでそれを行うことができます。

それがダックタイピングの利点です。動的型付けがすべての状況で使用する適切なパラダイムであるという意味ではありません。私の Groovy プロジェクトでは、型に関するコンパイラの警告が役立つと思われる状況では、Java に戻すのが好きです。

于 2010-02-16T11:20:42.417 に答える
1

ダックタイピングが静的タイピングよりも生産性が高いというわけではありませんが、単に異なるだけです。静的型付けでは、データが正しい型であることを常に心配する必要があります。Java では、正しい型へのキャストによってデータが表示されます。ダックタイピングでは、適切なメソッドがある限り型は問題にならないため、型間のキャストと変換の面倒な作業が大幅に削減されます。

于 2008-09-07T00:31:58.897 に答える