# クイックスタート

## Step 1

わざとガバナエラーを発生させてみよう！

簡単なロジックを Apex のみで記述し、手っ取り早くガバナエラーを再現します。

### 検証用の SFDX プロジェクトを作成

まずは SFDX プロジェクトを作成します。

{% code title="PowerShell" %}

```
sf generate project -n MyFunctionProject
cd MyFunctionProject
yarn install
code .
```

{% endcode %}

### 検証用の Apex クラスを作成

次に、検証用の Apex クラスを作成してみます。開発者コンソールでも良いですが、VS Code を利用することをおすすめします。

{% code title="force-app/main/default/classes/CaseDemo.cls" %}

```apex
public class CaseDemo {
  public static Integer countLoop(Integer numStart, Integer numEnd) {
    Integer result = numStart;
    while (result < numEnd) {
      result++;
    }
    return result;
  }
}
```

{% endcode %}

与えられた引数だけループするだけのプログラムになります。 例えば `CaseDemo.countLoop(0, 100)` と実行すると、100 回ループし、`100`を返却します。 単純なプログラムですね！

実際に実行してみましょう。VS Code を利用して Apex を匿名実行し、デバッグログを見てみます。

{% code title="scripts/apex/check-governor.apex" %}

```apex
/**
 * check-governor.apex
 */
String result = '';
result += '\n';
result += '\n';

// 引数を自由に変えて Maximum CPU time を確認
result += CaseDemo.countLoop(0, 2000000);

result += '\n';

System.debug('\n==================================================');
System.debug(result);
System.debug('\n==================================================');
```

{% endcode %}

![デバッグログの例](https://3562622291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FXVDsscm3zJU3RzlGxSFo%2Fuploads%2F4FnsGAuh7iyHBuVmgVAt%2Fimage.png?alt=media\&token=a5da9bd3-c447-44ac-a74f-15121cff7d36)

### 演習問題 1.1

必ず正常終了するようなループ回数は、何回未満でしょうか？

{% hint style="info" %}
**Hint:** `CaseDemo.countLoop` の第 1 引数は `0` に固定し、第 2 引数を色々と変化させて実行してみましょう。
{% endhint %}

### 演習問題 1.2

必ずガバナエラーが発生するようなループ回数は、何回以上でしょうか？

{% hint style="info" %}
**Hint:** 演習問題 1.1 をやりながら、引数の数値を 1 桁ずつ増やしたり半分にしたり色々試してみてください。
{% endhint %}

## Step 2

同じロジックを Salesforce Functions に置き換えてみよう！

今度は同じロジックを JavaScript で記述し、ガバナエラーを回避できることを簡単に確認します。

### Salesforce Functions で Hello, World！！

次のコマンドを実行して、 Salesforce Functions の雛形を用意しましょう。

{% code title="PowerShell" %}

```
sf generate function -n myfunction -l javascript
```

{% endcode %}

何よりもまず、Hello World をしてみます。

{% code title="functions/myfunction/index.js" %}

```javascript
export default async function (event, context, logger) {
  const result = 'Hello, World!!';

  return result;
}
```

{% endcode %}

ローカルサーバで Salesforce Functions を起動させます。 VS Code のターミナルから次のコマンドを実行します。

{% code title="PowerShell" %}

```
cd functions/myfunction
sf run function start
```

{% endcode %}

ローカルサーバで Salesforce Functions を起動させたまま、別のターミナルから Salesforce Functions を呼び出します。 `-p` でパラメータを渡すことができます。

{% code title="PowerShell" %}

```
sf run function -l http://localhost:8080 -p '{}'
```

{% endcode %}

![Hello World](https://3562622291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FXVDsscm3zJU3RzlGxSFo%2Fuploads%2FA5qTER1Yqq8QRyuSbPJJ%2F20220511_001.png?alt=media\&token=4280d17f-b3f1-444e-989b-56b3126160f0)

いい感じにできましたね。次は、Step1 と同様のロジックを記述し、再実行してみます。

{% code title="functions/myfunction/index.js" %}

```javascript
export default async function (event, context, logger) {
  // const result = 'Hello, World!!';

  let result = event.data.numStart;
  while (result < event.data.numEnd) {
    result++;
  }

  return result;
}
```

{% endcode %}

{% code title="PowerShell" %}

```
sf run function -l http://localhost:8080 -p '{"numStart":0,"numEnd":2000000}'
```

{% endcode %}

![実効結果](https://3562622291-files.gitbook.io/~/files/v0/b/gitbook-x-prod.appspot.com/o/spaces%2FXVDsscm3zJU3RzlGxSFo%2Fuploads%2F6ZSSZ7l2wx79DGWYL75F%2F20220510_001.png?alt=media\&token=42fd7d4e-79a0-4ffa-9347-df39b7f2971b)

### 演習問題 2.1

Step1 でガバナエラーだった回数をループさせた場合、エラーは発生するでしょうか？

{% hint style="info" %}
**Hint:** たとえば 2,000 万回ループさせたい場合は、 `{"numStart":0,"numEnd":20000000}` をパラメータとして渡して実行してみましょう。
{% endhint %}

## Step 3

他にも色々なサンプルコードを動かしてみよう！

ここまでは Salesforce のデータを扱うロジックがなかったのでいまいちでしたが、もちろん Salesforce Functions でも Salesforce のデータを扱うことができます。しかも、けっこう簡単に書けてしまうことを体感してみましょう。

### Salesforce からデータを検索！

`context.org.dataApi.query()` を実行するだけです。

{% code title="functions/myfunction/index.js" %}

```javascript
export default async function (event, context, logger) {
  // const result = 'Hello, World!!';

  // let result = event.data.numStart;
  // while (result < event.data.numEnd) {
  //   result++;
  // }

  const result = await context.org.dataApi.query(
    'SELECT Id, Name FROM Account'
  );

  return result;
}
```

{% endcode %}

{% hint style="danger" %}
**Hint:** Salesforce Functions を使ったとしても、5 万件以上を検索しようとするとガバナエラーが発生してしまいます。
{% endhint %}

### Salesforce にデータを登録！

`context.org.dataApi.newUnitOfWork().registerCreate()` を実行します。

{% code title="functions/myfunction/index.js" %}

```javascript
export default async function (event, context, logger) {
  // const result = 'Hello, World!!';

  // let result = event.data.numStart;
  // while (result < event.data.numEnd) {
  //   result++;
  // }

  const uow = context.org.dataApi.newUnitOfWork();
  const referenceId = await uow.registerCreate({
    type: 'Case',
    fields: {
      subject: 'demo',
    },
  });
  const response = await context.org.dataApi.commitUnitOfWork(uow);
  const caseId = response.get(referenceId).id;

  const result = await context.org.dataApi.query(
    //   'SELECT Id, Name FROM Account'
    `SELECT Id, CaseNumber,Subject FROM Case WHERE Id = '${caseId}'`
  );

  return result;
}
```

{% endcode %}

{% hint style="danger" %}
**Hint:** Salesforce Functions を使ったとしても、150 件以上を一括登録しようとするとガバナエラーが発生してしまいます。
{% endhint %}

### 演習問題 3.1

他にどんなことができそうか、調べてみましょう。

> [Salesforce SDK for Node.js Functions](https://developer.salesforce.com/docs/platform/functions/guide/NODE_README.html)
