web-dev-qa-db-ja.com

グラフィカルUIのみを構築する1500 LOCメソッドのリファクタリング

私は現在、基本的にUIを構築するだけのメソッドをリファクタリングする方法について頭を悩ませています。

この方法は、1500行を超えるコード(LOC)の長さであり、カウントされます。それは成長しました、これにどのように取り組むかという計画はありませんでした。あなたかもしれないこれはおなじみだと思う。

とにかく、それは基本的に次のような小さな方法の1つにすぎません。

    .
    .
    .

    # null checks
    null_checks_bx = Box(True)

    null_checks_ck = CheckBox()
    null_checks_ck.set_text('Null checks throwing exceptions of type:')

    if 'doNullChecks' in options:
        null_checks_ck.set_active(options['doNullChecks'])
    else:
        null_checks_ck.set_active(True)

    # dict to sorted list: extract values from dict by list comprehension
    exceptions = sorted([exception.get_full_name() for exception in JavaTypes.exception_types])

    null_checks_se = Selector()
    null_checks_se.add_items(exceptions)
    null_checks_se.set_enabled(null_checks_ck.get_active())

    if 'nullChecksExceptionFullClassName' in options:
        null_checks_se.set_value(options['nullChecksExceptionFullClassName'])
    else:
        # default to first entry
        #(defaulting to doEquals = True and doHashCode = True by using hardcoded Commons Lang implies availability of Commons Lang NullArgumentException)
        null_checks_se.set_value(JavaTypes.exception_types[0].get_full_name())

    # callback
    Callbacks.sync_model_active_status(null_checks_ck, null_checks_se)

    null_checks_ck.add_clicked_callback(lambda: Callbacks.sync_model_active_status(null_checks_ck, null_checks_se))

    null_checks_bx.add(Label(indent), False, True)  # dummy indent label
    null_checks_bx.add(null_checks_ck, False, True)
    null_checks_bx.add(null_checks_se, False, True)

    # relationship entity class constructor calls
    relationship_constructor_calls_bx = Box(True)
    #relationship_constructor_calls_bx.set_spacing(5)
    #relationship_constructor_calls_bx.set_padding(3)

    relationship_constructor_calls_ck = CheckBox()
    relationship_constructor_calls_ck.set_text('Instantiate relationship entities (if all necessary columns present)')

    if 'doRelationshipConCalls' in options:
        relationship_constructor_calls_ck.set_active(options['doRelationshipConCalls'])
    else:
        relationship_constructor_calls_ck.set_active(False)

    relationship_constructor_calls_bx.add(Label(indent), False, True)  # dummy indent label
    relationship_constructor_calls_bx.add(relationship_constructor_calls_ck, False, True)

    # relationship not-null checks: this is an option independent of the null checks!
    relationship_not_null_checks = Box(True)
    #relationship_not_null_checks.set_spacing(5)
    #relationship_not_null_checks.set_padding(3)

    relationship_not_null_checks_ck = CheckBox()
    relationship_not_null_checks_ck.set_text('Not-null checks before relationship instantiation')

    relationship_not_null_checks_ck.set_enabled(relationship_constructor_calls_ck.get_active() and not null_checks_ck.get_active())

    if 'doRelationshipNotNullChecks' in options:
        relationship_not_null_checks_ck.set_active(options['doRelationshipNotNullChecks'])
    else:
        relationship_not_null_checks_ck.set_active(True)

    # callback
    Callbacks.sync_convenience_constructor_options(null_checks_ck, relationship_constructor_calls_ck, relationship_not_null_checks_ck)

    null_checks_ck.add_clicked_callback(lambda: Callbacks.sync_convenience_constructor_options(null_checks_ck, relationship_constructor_calls_ck, relationship_not_null_checks_ck))
    relationship_constructor_calls_ck.add_clicked_callback(lambda: Callbacks.sync_convenience_constructor_options(null_checks_ck, relationship_constructor_calls_ck, relationship_not_null_checks_ck))

    relationship_not_null_checks.add(Label(indent), False, True)  # dummy indent label
    relationship_not_null_checks.add(Label(indent), False, True)  # dummy indent label
    relationship_not_null_checks.add(relationship_not_null_checks_ck, False, True)

    # build final box
    checks_bx = Box(False)
    checks_bx.set_spacing(5)
    #checks_bx.set_padding(3)
    checks_bx.set_homogeneous(True)
    checks_bx.add(omit_auto_increment_columns_bx, False, True)
    checks_bx.add(omit_auto_timestamp_columns_bx, False, True)
    checks_bx.add(null_checks_bx, False, True)
    checks_bx.add(relationship_constructor_calls_bx, False, True)
    checks_bx.add(relationship_not_null_checks, False, True)

    # callback
    Callbacks.sync_model_active_status(convenience_constructors_ck, checks_bx)

    convenience_constructors_ck.add_clicked_callback(lambda: Callbacks.sync_model_active_status(convenience_constructors_ck, checks_bx))

    # need wrapped box for Panel class
    constructors_bx = Box(False)
    constructors_bx.set_spacing(5)
    constructors_bx.set_padding(3)
    #constructors_bx.set_homogeneous(True)
    constructors_bx.add(convenience_constructors_bx, False, True)
    constructors_bx.add(checks_bx, False, True)

    constructors_pn = Panel(TitledGroupPanel)
    constructors_pn.set_title('Constructors')
    constructors_pn.add(constructors_bx)

    # getters and setters
    is_conversion_bx = Box(True)
    #is_conversion_bx.set_spacing(3)
    #is_conversion_bx.set_padding(3)

    is_conversion_ck = CheckBox()
    is_conversion_ck.set_text('Convert respective column names starting with "is_"')
    is_conversion_ck.set_tooltip("Column is_incognito => getter isIncognito() (not getIsIncognito()) and setter setIncognito()")

    if 'doIsConversion' in options:
        is_conversion_ck.set_active(options['doIsConversion'])
    else:
        is_conversion_ck.set_active(True)

    is_conversion_bx.add(is_conversion_ck, False, True)

    # generate code for relationship getters and setters to synchronize with column fields
    sync_relationship_pk_fields_bx = Box(True)
    #sync_relationship_pk_fields_bx.set_spacing(3)
    #sync_relationship_pk_fields_bx.set_padding(3)

    sync_relationship_pk_fields = CheckBox()

    .
    .
    .

あなたはポイントを取得します。

私にはわからないのは、コードがより管理しやすく、より理解しやすくなるように、このメソッドを分割するための基準が何であるかということです。

ここでのベストプラクティスは何ですか?

定期的なタイプのパネルとウィジェットを作成するいくつかのメソッドを作成することはできますが、これは私が実際の利益を確認できないものに対してかなり面倒な作業になるでしょう。

繰り返しますが、グラフィカルUIのみを構築する、大きくて不器用なメソッドに対するいくつかの有用で実用的なアプローチは何ですか?

ありがとう

PS:ああ、ところで、UIは標準のウィンドウアプリケーション(Webなし)の単一のダイアログであり、このダイアログには6つのタブがあり、主にチェックボックス、ラジオボタン、テキストボックスが含まれています。これは、ユーザーが多くのオプションを選択できるコード生成プラグインです。プラグインを再び実行するとすぐに画像を投稿するかもしれません...

8
Kawu

あなたのコードには、ここであなたが有利に使用できる1つの機能があるようです:それらすべてのグループ化コメント。これらのコメントは、 より小さなメソッドを抽出する によってメソッドをチャンクに分割するための基礎として使用できます。各チャンクを独自のメソッドに取り出し、コードの元の場所からそのメソッドを呼び出します。

これらの要素を引き出し始めると、自然に重複が見つかるか、いくつかのメソッド間の強い関係が自然に見つかるでしょう。重複を見つけたら、それをヘルパーメソッドに抽出して、コードをDRYにします。自然な関係の境界を見つけたら、それらをより密接に関連する機能の個別のクラスに分割できます。

以下では、たとえば、ヌルチェック部分を構築するためのロジックを引き出し始めました。私はそれをメソッドとして抽出し、より適切な名前が必要ないくつかの部分を分割し、メソッド内のすべての変数の名前空間を解除しました。できることはもっとたくさんありますが、それは読者の練習問題として残されています。

def add_indent_label(self, box):
    box.add(Label(indent), False, True)

def get_null_checks(self, options):
    box = Box(True)

    checkbox = CheckBox()
    checkbox.set_text('Null checks throwing exceptions of type:')

    if 'doNullChecks' in options:
        checkbox.set_active(options['doNullChecks'])
    else:
        checkbox.set_active(True)

    exceptions = self.get_exceptions()

    selector = Selector()
    selector.add_items(exceptions)
    selector.set_enabled(checkbox.get_active())

    if 'nullChecksExceptionFullClassName' in options:
        selector.set_value(options['nullChecksExceptionFullClassName'])
    else:
        selector.set_value(self.get_first_exception())

    # callback
    Callbacks.sync_model_active_status(checkbox, selector)
    checkbox.add_clicked_callback(lambda: Callbacks.sync_model_active_status(checkbox, selector))

    self.add_indent_label(box);
    box.add(checkbox, False, True)
    box.add(selector, False, True)

    return box

def get_exceptions(self):
    return sorted([exception.get_full_name() for exception in JavaTypes.exception_types])

# This could probably have a better name
def get_first_exception(self):
    #(defaulting to doEquals = True and doHashCode = True by using hardcoded Commons Lang implies availability of Commons Lang NullArgumentException)
    return JavaTypes.exception_types[0].get_full_name()

そして、元のコードでは、次のようになります。

null_checks_bx = self.get_null_checks(options)
27
cbojar