Skip to content

Commit e3574fa

Browse files
authored
feat(CONTRIBUTING_EXPENSE): Open Collectiveの手引きを追加 (#1764)
* feat(CONTRIBUTING_EXPENSE): Open Collectiveの手引きを追加 * update * update
1 parent e950330 commit e3574fa

File tree

2 files changed

+214
-0
lines changed

2 files changed

+214
-0
lines changed

CONTRIBUTING_EXPENSE.md

Lines changed: 141 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,141 @@
1+
# Contributing Expenses Policy
2+
3+
JavaScript Primer(jsprimer)はOpen Collectiveを通じて資金を募っています。
4+
この資金は、jsprimerへContributeしてくれた方々に対して、費用を支払うために使われます。
5+
6+
- [JavaScript Primer - Open Collective](https://opencollective.com/jsprimer)
7+
- [JavaScript Primerスポンサー · JavaScript Primer #jsprimer](https://jsprimer.net/intro/sponsors/)
8+
9+
このガイドでは、jsprimerへのContributeした場合の費用をOpen Collectiveで請求する方法について説明します。
10+
11+
## 費用の計算方法
12+
13+
jsprimerへのContributeしたタスクに対してPointを設定し、そのPointに基づいて金額を計算します。
14+
15+
### タスクに対するPoint
16+
17+
作業量に対する基準としてフィボナッチ数列のPointを設定する
18+
19+
| Point | Description |
20+
|-------|-----------------------|
21+
| 0 | 些細な変更 |
22+
| 1 | 2 よりは簡単 |
23+
| 2 | 大体1日分やると終わる想定 |
24+
| 3 | 2 よりは難しい |
25+
| 5 | かなり難しい |
26+
| 8 | 難易度がとても高いので、できる人は限られる |
27+
28+
Issueが適切に分割されていれば、5や8はほとんど出てこない想定です。
29+
5以降はブレが大きいので、参考程度のPointとして扱います。
30+
31+
📝 元ネタはLinearの[Estimates – Linear Docs](https://linear.app/docs/estimates)
32+
33+
### Pointの例
34+
35+
Pointはやや主観的になってしまうが、既存のIssueを比較してどの程度のPointになるかを判断する。
36+
37+
- Point 1:
38+
- [fix(nodecli): update to marked@14 by azu · Pull Request #1760 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/pull/1760)
39+
- ほとんど置換で終わるような変更
40+
- [fix: Node.js v18.12.0 LTSにアップデート by azu · Pull Request #1496 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/pull/1496)
41+
- やり方がだいたい定型化されてる変更
42+
- Point 2:
43+
- [feat(ecmascript): Stage 2.7を追加 by azu · Pull Request #1743 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/pull/1743)
44+
- 文章自体はほとんどないが、多少調べる必要がある
45+
- [mocha を`node:test`に変更する by windchime-yk · Pull Request #1737 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/pull/1737)
46+
- 1 つのセクションを書き直すような変更
47+
- [feat(map-and-set): `Map.groupBy`静的メソッドの追加 by azu · Pull Request #1751 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/pull/1751)
48+
- 1 つのセクションを追加する変更
49+
- [feat: ErrorCause への対応 by himanoa · Pull Request #1732 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/pull/1732)
50+
- 1 つのセクションを追加する変更
51+
- Point 3:
52+
- [feat(array): Change Array by copy の対応 by azu · Pull Request #1679 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/pull/1679)
53+
- 複数のセクションにまたがる変更
54+
- Point 5:
55+
- [fix(nodecli): commander パッケージ を `node:util``parseArg` に変更 by azu · Pull Request #1757 · asciidwango/js-primer](https://github.com/asciidwango/js-primer/pull/1757)
56+
- 章全体にまたがる変更
57+
- かなり影響範囲が広く、書き直しも多い変更
58+
59+
### 金額の計算方法
60+
61+
金額は次のツールで計算できる。
62+
63+
```bash
64+
$ node ./tools/calc-contribute-expense.mjs --point <number>
65+
```
66+
67+
#### 金額の計算式
68+
69+
jsprimerの年間更新コストは、だいたい30日分の作業量になるように設定している。
70+
71+
- [JavaScript Primer 改訂2版をリリースしました!/JavaScript Primerはなぜ更新され続けるのか? | Web Scratch](https://efcl.info/2023/06/09/jsprimer-v2/)
72+
73+
Pointに直すと、年間の作業量のPointは60 Point程度になる。
74+
75+
年間の予算はOpen Collectiveの"推定年間予算(Estimated annual budget)"を参照する
76+
77+
- [JavaScript Primer - Open Collective](https://opencollective.com/jsprimer)
78+
79+
1 Pointあたりの金額は次の計算式で求める。
80+
81+
```js
82+
const yearlyEstimatedBudget = _; // Open Collectiveの推定年間予算($ドル)
83+
const yearlyWorkloadPoints = 60; // 1年間のPoints
84+
const onePointCost = yearlyEstimatedBudget / yearlyWorkloadPoints;
85+
console.log({ onePointCost }); // => 1 Pointあたりの金額($ドル)
86+
const taskPoint = _; /// タスクのPoint
87+
const cost = onePointCost * taskPoint;
88+
console.log({ cost }); // => タスクの金額($ドル)
89+
```
90+
91+
Example: 推定年間予算が $2,367 で、タスクが 2 Points の場合
92+
93+
```js
94+
95+
const yearlyEstimatedBudget = 2_367; // Open Collectiveの推定年間予算($ドル)
96+
const yearlyWorkloadPoints = 60; // 1年間のPoints
97+
const onePointCost = yearlyEstimatedBudget / yearlyWorkloadPoints;
98+
console.log({ onePointCost }); // => $39.45
99+
100+
const costOfPoint = 2; /// 2 Points
101+
const cost = onePointCost * costOfPoint;
102+
console.log({ cost }); // => $78.9
103+
```
104+
105+
### 金額を確定するタイミング
106+
107+
作業が終わったタイミングで計算して、その月のコストをまとめて申請する。
108+
Open Collectiveからの支払いは2週間ごとに行われるため、月ごとにまとめて請求する。
109+
110+
## 費用の請求方法
111+
112+
計算式に基づいた金額をOpen Collectiveで請求する手順
113+
114+
1. <https://opencollective.com/jsprimer/expenses/new> にアクセス
115+
2. "Invoice"を選択
116+
3. 請求者の情報と支払い先(銀行口座またはPayPal)を入力
117+
4. "Next"をクリック
118+
5. 請求書の画面で "Expense title" に `Development and maintenance (YYYY-DD)` と入力
119+
6. 請求書の画面で "Set invoice details"の "Description" に `Contribute to jsprimer (YYYY-DD)` と入力
120+
7. 請求書の画面で "Date" には 今日の日付を入力
121+
8. 請求書の画面で "Amount" は USD を選択し、計算した金額を入力
122+
- 自動的にExpense Currencyで選択したJPYに変換された金額が表示されます
123+
9. "Next"をクリック
124+
10. Add notesに次の内容を入力
125+
```
126+
Contribute to jsprimer
127+
- Commits: https://github.com/asciidwango/js-primer/commits?author=<GitHubアカウント>&since=月の初めの日&until=月の最終日
128+
```
129+
130+
```
131+
Contribute to jsprimer
132+
- Commits: https://github.com/asciidwango/js-primer/commits?author=azu&since=2024-08-01&until=2024-08-31
133+
```
134+
11. 確認して "Submit expense"をクリック
135+
136+
あとは管理者がApproveするまで待つと、その後Open Collectiveから支払われます。
137+
138+
Note:
139+
140+
- 入力した個人情報は公開されません
141+
- 公開されるのは、Expense titleとDescriptionとOpen Collectiveのアカウント情報のみです

tools/calc-contribute-expense.mjs

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
#!/usr/bin/env node
2+
3+
import { parseArgs } from "node:util";
4+
5+
const HELP = `
6+
コラボレーターの請求額を計算するツール
7+
8+
Usage: ./calc-contribute-expense.js --point <number>
9+
10+
Options:
11+
12+
--point, -p <number> 計算したいポイント数
13+
--help, -h ヘルプを表示
14+
15+
`;
16+
const cli = parseArgs({
17+
options: {
18+
point: {
19+
type: "string",
20+
alias: "p",
21+
},
22+
help: {
23+
type: "boolean",
24+
alias: "h",
25+
}
26+
}
27+
});
28+
if (cli.values.help) {
29+
console.log(HELP);
30+
process.exit(0);
31+
}
32+
33+
const point = cli.values.point ? parseInt(cli.values.point, 10) : null;
34+
if (!point) {
35+
console.error("--point <number> を指定してください");
36+
process.exit(1);
37+
}
38+
const query = `query account($slug: String) {
39+
account(slug: $slug) {
40+
name
41+
slug
42+
stats{
43+
yearlyBudget {
44+
currency
45+
value
46+
valueInCents
47+
}
48+
}
49+
}
50+
}`;
51+
const slug = "jsprimer";
52+
const response = await fetch("https://api.opencollective.com/graphql/v2", {
53+
method: "POST",
54+
headers: {
55+
"Content-Type": "application/json",
56+
},
57+
body: JSON.stringify({
58+
query,
59+
variables: { slug },
60+
}),
61+
});
62+
const { data } = await response.json();
63+
const yearlyBudgetCents = data.account.stats.yearlyBudget.valueInCents;
64+
const yearlyWorkloadPoints = 60; // 1年間のPoints
65+
const onePointCostCents = yearlyBudgetCents / yearlyWorkloadPoints;
66+
const costCents = onePointCostCents * point;
67+
console.log(`コラボレーターの請求額: $${costCents / 100}`);
68+
console.table({
69+
"1年間の予算": `$${yearlyBudgetCents / 100}`,
70+
"1年間のWorkload Points": yearlyWorkloadPoints,
71+
"1ポイントあたりのコスト": `$${onePointCostCents / 100}`,
72+
"請求額": `$${costCents / 100}`,
73+
});

0 commit comments

Comments
 (0)