

翻訳は機械翻訳により提供されています。提供された翻訳内容と英語版の間で齟齬、不一致または矛盾がある場合、英語版が優先します。

# ソリューション
<a name="java-flow-making-changes-solutions"></a>

後方互換性のない変更を回避するには、次のソリューションを使用します。詳細については、「[Making Changes to Decider Code](java-flow-making-changes-decider-code.md)」(ディサイダーコードの変更) および「[シナリオの例](java-flow-making-changes-example-scenario.md)」を参照してください。

## バージョニングの使用
<a name="use-versioning"></a>

このソリューションでは、ディサイダーを新しいクラスにコピーして、ディサイダーを変更し、新しいワークフローバージョンでそのディサイダーを登録します。

`VersionedDecider.java`

```
package sample.v2;
 
import com.amazonaws.services.simpleworkflow.flow.DecisionContext;
import com.amazonaws.services.simpleworkflow.flow.DecisionContextProviderImpl;
import com.amazonaws.services.simpleworkflow.flow.WorkflowClock;
import com.amazonaws.services.simpleworkflow.flow.annotations.Execute;
import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow;
import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions;
 
import sample.Input;
 
@Workflow
@WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 60, defaultTaskStartToCloseTimeoutSeconds = 5)
public interface Foo {
 
    @Execute(version = "2")
    public void sample(Input input);
 
    public static class Impl implements Foo {
 
        private DecisionContext decisionContext = new DecisionContextProviderImpl().getDecisionContext();
        private WorkflowClock clock = decisionContext.getWorkflowClock();
 
        @Override
        public void sample(Input input) {
            System.out.println("Decision (V2) WorkflowId: " + decisionContext.getWorkflowContext().getWorkflowExecution().getWorkflowId());
            clock.createTimer(5);
        }
 
    }
 
}
```

更新後の Java コードでは、2 番目のディサイダーワーカーによって、いずれのバージョンのワークフローも実行されるため、バージョン `2` の変更とは別に、処理中の実行を続けることができます。

`RunVersionedDecider.java`

```
package sample;
 
import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker;
 
public class VersionedChange extends SampleBase {
 
    public static void main(String[] args) throws Exception {
        new VersionedChange().run();
    }
 
    public void run() throws Exception {
        // Start the first version of the decider, with workflow version 1
        WorkflowWorker before = new WorkflowWorker(service, domain, taskList);
        before.addWorkflowImplementationType(sample.v1.Foo.Impl.class);
        before.start();
 
        // Start a few executions with version 1
        startFiveExecutions("Foo.sample", "1", new Input());
 
        // Stop the first decider worker and wait a few seconds 
        // for its pending pollers to match and return
        before.suspendPolling();
        sleep(2000);
 
        // At this point, three executions are still open, with more decisions to make
 
        // Start a worker with both the previous version of the decider (workflow version 1) 
        // and the modified code (workflow version 2)
        WorkflowWorker after = new WorkflowWorker(service, domain, taskList);
        after.addWorkflowImplementationType(sample.v1.Foo.Impl.class);
        after.addWorkflowImplementationType(sample.v2.Foo.Impl.class);
        after.start();
 
        // Start a few more executions with version 2
        startFiveExecutions("Foo.sample", "2", new Input());
 
        printExecutionResults();
    }
 
}
```

プログラムを実行すると、実行はすべて正常に完了します。

## 機能フラグの使用
<a name="use-feature-flags"></a>

後方互換性の問題のもう 1 つのソリューションは、ワークフローバージョンではなく、入力データに基づき分岐するために、同じクラスの 2 つの実装をサポートするコードを分岐することです。

このアプローチを使用する場合は、機密的な変更を行う度に、入力オブジェクトにフィールドを追加するか、既存フィールドを変更します。移行前にスタートする実行の場合、入力オブジェクトにフィールドは作成されません (または異なる値が含まれます)。このように、バージョン番号を増やす必要はありません。

**注記**  
新しいフィールドを追加する場合は、JSON の逆シリアル化プロセスに後方互換性があることを確認します。フィールドの導入前にシリアル化されたオブジェクトは、移行すると正常に逆シリアル化されます。フィールドがない場合、`null` 値が JSON に設定されるため、必ず boxed 型 (`boolean` ではなく `Boolean`) を使用し、値が `null` のケースに対応します。

`FeatureFlagDecider.java`

```
package sample.v1.featureflag;
 
import com.amazonaws.services.simpleworkflow.flow.DecisionContext;
import com.amazonaws.services.simpleworkflow.flow.DecisionContextProviderImpl;
import com.amazonaws.services.simpleworkflow.flow.WorkflowClock;
import com.amazonaws.services.simpleworkflow.flow.annotations.Execute;
import com.amazonaws.services.simpleworkflow.flow.annotations.Workflow;
import com.amazonaws.services.simpleworkflow.flow.annotations.WorkflowRegistrationOptions;
 
import sample.Input;
 
@Workflow
@WorkflowRegistrationOptions(defaultExecutionStartToCloseTimeoutSeconds = 60, defaultTaskStartToCloseTimeoutSeconds = 5)
public interface Foo {
 
    @Execute(version = "1")
    public void sample(Input input);
 
    public static class Impl implements Foo {
 
        private DecisionContext decisionContext = new DecisionContextProviderImpl().getDecisionContext();
        private WorkflowClock clock = decisionContext.getWorkflowClock();
 
        @Override
        public void sample(Input input) {
            System.out.println("Decision (V1 feature flag) WorkflowId: " + decisionContext.getWorkflowContext().getWorkflowExecution().getWorkflowId());
            clock.createTimer(5);
            if (!input.getSkipSecondTimer()) {
                clock.createTimer(5);
            }
        }
 
    }
}
```

更新後の Java コードでは、ワークフローのコードはいずれのバージョンも、バージョン `1` として登録されます。ただし、移行後、新しい実行は、`true` に設定されている入力データの `skipSecondTimer` フィールドからスタートします。

`RunFeatureFlagDecider.java`

```
package sample;
 
import com.amazonaws.services.simpleworkflow.flow.WorkflowWorker;
 
public class FeatureFlagChange extends SampleBase {
 
    public static void main(String[] args) throws Exception {
        new FeatureFlagChange().run();
    }
 
    public void run() throws Exception {
        // Start the first version of the decider
        WorkflowWorker before = new WorkflowWorker(service, domain, taskList);
        before.addWorkflowImplementationType(sample.v1.Foo.Impl.class);
        before.start();
 
        // Start a few executions
        startFiveExecutions("Foo.sample", "1", new Input());
 
        // Stop the first decider worker and wait a few seconds 
        // for its pending pollers to match and return
        before.suspendPolling();
        sleep(2000);
 
        // At this point, three executions are still open, with more decisions to make
 
        // Start a new version of the decider that introduces a change 
        // while preserving backwards compatibility based on input fields
        WorkflowWorker after = new WorkflowWorker(service, domain, taskList);
        after.addWorkflowImplementationType(sample.v1.featureflag.Foo.Impl.class);
        after.start();
 
        // Start a few more executions and enable the new feature through the input data
        startFiveExecutions("Foo.sample", "1", new Input().setSkipSecondTimer(true));
 
        printExecutionResults();
    }
 
}
```

プログラムを実行すると、実行はすべて正常に完了します。