複雑な仕組みと向き合い、会計システムをリプレイスした話

この記事は、「[ランサーズ Advent Calendar 2018](https://qiita.com/advent-calendar/2018/lancers)」の24日目の記事になります。
前日の記事は、@godgarden の「[ランサーズに出戻って1年。担当した開発プロジェクトを振り返る。](https://engineer.blog.lancers.jp/2018/12/comeback-lancers/)」でした。

# はじめに

### この記事の目的

今年、ランサーズの会計システムのリプレイスを行ったので、リプレイスに至った背景、どのようなシステムにしたのかを書いていきます。

世の中に技術的なトピックはいろいろ上がってますが、ウェブサービスにおける会計システムの記事はあまりなかったので、こう言った課題に向き合っている方の参考になればと思います。

## なぜ会計が必要か

どんな事業・サービスにも継続していくには、運営するための利益が必要であり、その売上を管理するためには正しい売上の集計が必要です。このあたりは、どんなスタートアップのサービスでも気にして運営されていると思います。

そして、会社がパブリックになるにあたり、売上だけでなく、より厳密な会計データの管理、運営が望まれ、必須になっていきます。これは、いわゆる決算処理をするためであり、決算処理をするためには、財務諸表と言われる損益計算書（PL）・貸借対応表（BS）という資料を作ります。ここに現れる数値は正しくなければなりません。

今回は、ランサーズというサービスにおけるこの会計にまつわるデータ・システムについてどのように構築し、運営しているのかを紹介したいと思います。

# リプレイスに至った背景

## 2種類のユーザーが存在するランサーズの複雑な仕組み

一方的にお金を支払うだけのECサイトでは、ユーザーは購入者という1種類のユーザーだけですが、ランサーズは、お仕事をお願いしたい法人（**クライアント**）と、お仕事をしたい人（**ランサー**）の**2種類のユーザー**が存在します。

提供しているサービスとしては、ランサーズ上でマッチングし、納品、お支払いといった実際のお仕事の取引をウェブ上で行えるプラットフォームです。お仕事を扱う以上、お金という情報は切っても切れません。2種類のユーザーとお金を扱うという意味では、C2Cのオークションサイトやフリマアプリも同様の論点があると思います。

こういったように2種類のユーザーと、お金、そしてお支払いの決済手段という複数の変数と向き合う必要があります。ランサーズでの一連の大まかな処理の流れは以下のフロー図になります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/38134/d194287b-d8f0-4bdf-4329-b0465341bc80.png)（![image.png](https://qiita-image-store.s3.amazonaws.com/0/38134/41387285-7316-115d-0afd-fdc0a0f54352.png)マークが決済は発生する箇所）
このような2種類のユーザー、それぞれで発生する決済処理を会計のデータとして集計する必要があります。また、「仕事への仮払い」というステップにあるように、ランサーズでは、ランサーが安心して仕事ができるよう、仮払いの仕組みがあるため、仮払い状態のものは支払いのものとは別に集計する必要があります。

更に、ランサーズでは、

* クレジットカード
* 後払い
* PayPal
* 銀行振込

上記4つの支払い方法に対応おり、支払い方法によっても会計的な扱いが変わってくるので、4パターンのデータ集計を必要とします。

以前は、こういった複雑な仕組みをうまく整理できない中で運用しておりました。

## 過去の会計データの集計


ランサーズでは、過去、以下のような形で会計データの集計を行っていました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/38134/8349f329-12c6-73bc-c9fb-4e4341f7ec68.png)


ランサーズシステム上でPHPプログラムにて仕訳の元となるCSVファイルを複数種類生成し、メールで経理チームに連携。経理チームが手動で会計システムにインポートするデータの集計を行うというフローで運用しておりましたが、以下のような問題がありました。

* 集計データは、仕訳データではなく、経理チームが手動で `SUMIF()` などを活用して該当データを集計する作業をしていたため、処理ミスが入るリスクがあった
* 当初の集計データを設計から時間がたち、正確な資料もなく、取引ごとの仕訳の意図の確認が困難になっており、技術的負債ならぬ、**仕訳的負債** を抱えていた。

データは自動で生成されるため、会計用のデータ連携には、開発の運用コストはかかっていませんでしたが、経理側に、手動での集計コスト、データの確からしさを調査するコストが発生しており、非効率で、精神衛生上不健康な状態だったと言えます。

# リプレイスの方針

以下2つの意思決定からシステムの見直しを行う方針を決めました。

* **仕訳の完全見直し**を行い、デイリー決算ができるレベルを作る。
* 仕訳集計から、会計システムへの連携を**自動化**する。

## 仕訳の完全見直し

見直しにあたり、前述のフロー図をももとにサービスで発生する会計にまつわる取引を洗い出し、各取引と決済手段から発生する仕訳をまとめていきます。本当はもっと複雑で種類が多いのですが、簡単にまとめると以下のような表になります。

実際、ランサーズでは、上記のような取引が50種類以上になり、それが整理され、各仕訳が正しく説明できる状態に見直すことができました。

この取引一覧ごとに、取引の元になるデータの定義もまとめていきます。それが自然と仕様書の代わりにもなり、関係者への説明資料ともなりますので、知識の形式化にも繋がりますので、作ることを強くおすすめします。

上記のように、取引の一覧、支払い方法ごとの仕訳一覧、そして、支払い方法によっていは仕訳がない取引もあるなど、こうした形で整理されてないと関係者に伝えるのは非常に困難かと思います。

## 集計からインポートデータ生成を自動化する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/38134/8349f329-12c6-73bc-c9fb-4e4341f7ec68.png)

上記の図のように、元々のシステムではランサーズで発生したデータをPHPプログラムで各仕訳に必要な項目を集計してました。

これでは、仕訳データもなく、会計システムである勘定奉行へインポートするためのフォーマットの変換する仕組みもありませんでしたし、仕訳自体も完全に見直したため、既存に縛られる理由は一切ありません。**既存の仕組みは完全に捨て、1から作り直す意思決定**をしました。

# 構築

実際に設計したシステム、また、重要なデータ構造について、説明していきます。

## システムの構成

これまでは、Lancersのシステム上で前述のデータ集計を行ってましたが、以下のような形で、新システムを構築しました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/38134/1a176d12-29b7-7b13-9390-2cfe99ffc8a7.png)

* ランサーズでは、会計・仕訳という情報は関心ごとから外し、取引にまつわるデータを管理することに特化。
* 新会計連携システムでは、取引データをもとに、具体的な仕訳データを生成します。ランサーズでの取引のもとになる情報などは関心ごとからは排除しており、取引データのみから仕訳データを生成するシンプルなシステムです。

ちなみに、新システムをRailsにした理由は、開発効率を優先するためRailsを選びました。

## テーブルの構造

具体的なテーブル構造は以下のようになりました。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/38134/8295a9ab-1f82-2705-b525-3444d006c75d.png)

システムの構成通り、ランサーズでは、取引に関するデータのみ扱い、新会計連携システムでは、勘定科目から仕訳の明細データまで、会計にまつわるデータのみを扱います。

データの集計に関しては、日時のバッチ処理で行っています。随時発生する処理から動的に取引データを生成する方法もありますが、導入時のテストの際の集計のしやすさ、間違った際の出し直しやすさ、既存処理に取引の概念を入れることでコードの複雑性が増してしまう。などから別集計する方法としてます。

## 完成形

最終的なシステムと会計処理の流れは以下のような形となりました。
### Before
![image.png](https://qiita-image-store.s3.amazonaws.com/0/38134/8349f329-12c6-73bc-c9fb-4e4341f7ec68.png)

### After
![image.png](https://qiita-image-store.s3.amazonaws.com/0/38134/75b92721-53e6-2e77-ae9d-ebb8796215bc.png)

各システムでの責務が明確になり、人力がなくなり、処理全体の見通しがよくなりました。
処理フローの整備、取引一覧と仕訳一覧を作成したことでの仕様の整理ができたことも大きかったと思います。

# 付録: Tips集

全体の説明が終わったところで、このプロジェクトで起こった問題や得た知識をTips集として掲載しておきます。

## 間違った正規化問題

フレームワークを利用していると、テーブルに作成日、更新日というカラムは標準でつけるという仕組みがついてくると思います。この作成日があるから、処理日を明示的に保持しない取らないといった実装をしていました。

しかし、この作成日はあくまでデータを作成した日であり、処理日かどうかはわかりません。例えば、データの不備などがあり、後で作り直した場合、果たしてその作成日は処理日なのでしょうか？もし、バックデートで処理日に合わしたとした場合、では作成日はいつなのでしょうか？

処理日は作成日ではありません。多くの場合に、同じ値となることが多いからと言って意味の違うカラムを一つにまとめるのは、正規化ではないのです。冗長に見えても意思を持って明確に分けるべきです。

今回のリプレイス時に実際にこの問題があり、いくつかのテーブルの見直しを行いました。

## プログラムが仕様書だ！問題

スタートアップの会社は少数精鋭で忙しく、仕様書を整理する時間も無いでしょう。弊社もそうでした。そのため、特に決済にまつわる部分などはほとんど古くからいる私しか知らないような状況。知るためにはコードを読み解くしか無い。。。このような状況はいくつかのリスクを抱えます。

* 単に担当者が事故や離職すると詰む。（私は元気ですしやめるつもりは無いですよ）
* 知っている人に業務が偏る。
* レビューが甘くなる（知らないし、複雑なので、努力しても甘くなってしまう）

今回、最後の1つにおいて深く考えさせられました。いろんな忙しさに言い訳し、情報の整理を怠ってしまったことを深く反省しました。情報を個人が保持していくことで、もしかしたらその個人の会社としての重要性は上がるかもしれません。しかし、重要な部分は最大限、**形式値**にしていくことがリスクヘッジなのです。

## 専門家だからこそ職務を超える

これまで、エンジニアは技術のことだけ、経理は会計のことだけという形で、お互いがそれぞれの領域のプロフェッショナルとして会計についてやってきていました。

しかし、そうしたことで、お互いの持っている情報がわからず正しい設計ができてきませんでした。今回わかったことは、エンジニアでも仕訳を書くことで、本当にあるべき設計ができますし、経理担当もシステムの仕組みや処理フローを設計することで、正しい会計処理、データ検証ができます。

プロフェッショナルは**職能を超えたオーバーラップ** を覚えるとさらなる飛躍があると感じました。

# 最後に

今回のシステム変更を経て、現在安定稼働が進んでいます。また、こういう変更することで、既存の不具合もいくつか見つかり、システムの見直しの有効性を肌で感じています。

今後は、どういうサービスが発生しても、この処理テーブルさえ各システムで保持すれば、会計連携システム側で会計データが生成できる仕組みができたため、新規事業をスピーディに立ち上げる土台もできたと言えます！

別途、プロジェクトで発生したここでは言い難い話などは、ぜひ個別に意見公開できると嬉しいです。ぜひ [@intrudercl14](https://twitter.com/intrudercl14?lang=ja) までお声がけください。

会計に悩むどなたかの参考になれば幸いです。

最終日の明日は、「[エンジニアは実装と戦うより UI と戦った方が幸せになれる 〜 メンタルモデル駆動開発の TIPS 〜
] (https://qiita.com/numanomanu/items/4a3b48528a67b670b463) （@numanomanu）」 です。ぜひ御覧ください！

## 参考

説明画像の一部アイコンは [Icon-rainbowさん](https://icon-rainbow.com/) を利用させていただきました。