-
Notifications
You must be signed in to change notification settings - Fork 37
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
【植田】料金シミュレーションAPIの実装 #43
base: master
Are you sure you want to change the base?
Conversation
end | ||
|
||
def total_charge(ampere, usage) | ||
(basic_charge(ampere) + usage_charge(usage)).round |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
「電気代 端数」で検索すると、「電気料金の合計額は円未満切り捨て」というふうに出てきます。
業界人でなければ普通知らないと思うのですが、業界だと当たり前なので顧客から明示的に仕様が提示されることは稀です。ですのでこの辺はENECHANGEのエンジニアとしては、しっかりと把握しておかなければなりません。
その上で、端数も出すという仕様にすることもあり得るかもしれませんし、プロジェクトには何年もこの業界で働いている人もいれば、入社したばかりの方もいますし、顧客においても不慣れな方がいるかもしれませんので、やはり認識合わせをしておくのが無難ですね。
植田さんも、「明示的ではないな、わからないな」と思った際には自身のコメントとともにレビュー依頼をかけていただくのが無難かなと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほど、これは調べれば分かる事だったので自分の判断で四捨五入したのはミスですね、すいません、修正します。
it '正しい合計料金が計算される' do | ||
expect(tokyo_gas_plan.total_charge(30, 300)).to eq(expected_charge_30_300) | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
アンペア20を入れた時の異常系のテストも欲しいと思ったのですがいかがでしょうか。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
そうですよね、このファイルより手前で30未満が渡らないようにしていたので、そのバリデーションがない場合はここでエラーになってしまっていたのでどう書けば良いか分かりませんでした。
今回は設計ごと変更してこのファイルがなくなるので次回からテストが書けない場合は設計を疑おうと思います、ありがとうございます。
def initialize | ||
super('JXTGでんき') | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
弊社では何千というプランを管理しています。
この設計にしてしまうと、今後プランが増えた時に毎回プランモデルを作らないといけない気がしますがいかがでしょうか。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
チャレンジの説明の中にも下記のポイントが記載されていますので、すでに工夫されていたら、もっと楽になるようにお願いします!
「同様の料金体系のプランが対象プランに追加された場合も、ロジックを追加せずに済むようにしてください。」
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
了解です、ファクトリーパターンで書き直してみようと思います。
def self.providers_info(ampere) | ||
info = { | ||
tokyo_electric: TokyoElectricPlan.new.provider_info, | ||
loop: LoopPlan.new.provider_info |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
あまり固有名詞をハッシュのキーにしてハードコーディングしない方がいいと思います。プランが増えるごとに修正しないといけないので。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
了解です、他の点も含めて他の設計を考えてみます。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここは動的生成で書き換えました。
|
||
class ElectricPlan | ||
def initialize(provider) | ||
@data = InitializeData.new(provider) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
プランの数だけYAMLがロードされてしまいませんか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
providerを入れたら、基本料金や従量料金がinitializeされるという流れになっていますが本当にそうでしょうか。
東京電力さんは複数のプランがあり、それぞれ基本料金や従量料金が違いますよね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
重複ロードの部分はキャッシュで書き直しました。
initialize部分は迷走してるのでもう少々お待ちを。
private | ||
|
||
def prepare_provider_data(provider) | ||
load_provider(provider) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なぜload_providerはここで呼び出すのでしょうか。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
load_providersで複数のプロバイダーが混合してる状態のものを取り出し、
load_providerでプロバイダーごとに情報を分け、
prepare_provider_dataでプロバイダーごとに情報を整形、
のつもりでしたがこだわりはないので他の方法考えてみますね。
return false | ||
end | ||
true | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
このくらいのバリデーションであればactivemodelのvalidationを使った方がいいのかなと思うのですが、このようにすると何がメリットとしてありますか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここについては単にrailsの知識の無さからきてるものなので特に意図があったわけではありません。勉強して書き直します。
end | ||
|
||
def load_provider(provider) | ||
@provider_data = @providers_data[provider] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
prepared_dataとに似ていて紛らわしい気がしました。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
名前が紛らわしいというのもありますが、データの出どころだったり使い分けの仕方だったりが不明確な気がしました。他のエンジニアがprepared_dataからではなく@provider_dataからデータを取ってくる実装をしてきそうだなと思いましたが、多分そういう意図ではなくprepared_dataから必ず最終outputを出したいんですよね?
であれば命名やデータの作り方を少し工夫したいですね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
load_providersで複数のプロバイダーが混合してる状態のものを取り出し、
load_providerでプロバイダーごとに情報を分け、
prepare_provider_dataでプロバイダーごとに情報を整形、
のつもりでしたがこだわりはないので他の方法考えてみますね。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
おっしゃる通り、時間空いて見返したら自分以外が見たら直感的じゃないなと感じました。
不要な細分化をまとめて書き直してみます。
|
||
def generate_tiers | ||
@provider_data['tiers'].transform_keys do |key| | ||
['Infinity', '.inf'].include?(key) ? Float::INFINITY : key |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
'Infinity' なのか '.inf' なのかってどこで決まりますか?
揃えられるなら揃えてしまった方が、脳に優しい気がしますがいかがでしょうか。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
.infで渡ってくる場合にも対応できるように合わせて書いた事があったのでそのまま前回と同じ書き方をしてしまってました。今回のデータでは全てInfinityなので書き換えます。
{ | ||
basic_charges: generate_basic_charges, | ||
tiers: generate_tiers, | ||
**{ provider => generate_plan } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ここって以下の方が直感的じゃないですか?
plan: generate_plan
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
そうですね、書き直します。
|
||
class ElectricPlan | ||
def initialize(provider) | ||
@data = InitializeData.new(provider) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
providerを入れたら、基本料金や従量料金がinitializeされるという流れになっていますが本当にそうでしょうか。
東京電力さんは複数のプランがあり、それぞれ基本料金や従量料金が違いますよね。
@@ -0,0 +1,51 @@ | |||
# frozen_string_literal: true | |||
|
|||
class InitializeData |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Dataというのは可能な限り避けた方が良いです。具体的に何を初期化するのかに合わせて考えた方がよく、何とも名付けにくい場合は初期化するデータが雑多すぎないか、責務が広すぎないか疑った方が良いです。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほど、了解です!今回ymlから渡されるデータは料金プランに関係するものがメインなのでInitializeChargePlanで書き直してみようと思います。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
このDockerfile作成の意図はなんですか?
(説明を見る限り、ローカルマシン上で動作させているようですが。)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
これはrails newで自動作成されたのかなと。意図的に作ったものではありません。
@@ -0,0 +1,30 @@ | |||
# frozen_string_literal: true | |||
|
|||
class Validator |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
私はこれがModel層にある方が自然だと感じたのですが、なんでだと思いますか?
(Service層でも全然問題ないので、実装はそのままで良いです!)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
なるほど、Activeモデルのバリデーション機能を使っているからでしょうか?
@ampere = params[:ampere].to_i | ||
@usage = params[:usage].to_i |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
私はこの変換が乱暴だと思うんですが、なんでだと思いますか?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
おっしゃる通りですね、ここに.to_i出来ない値が入る場合というのはエラーを出したい時かなと感じました。
今試したらhttp://127.0.0.1:3000/api/v1/plans/all/30/あ
で"あ"が0に変換されて意図しないレスポンスをしていたので修正します。
パラメータに文字列が渡ってきた場合のバリデーションとそのテスト追加
概要
serverside_challenge_1 を実装しました、レビューお願いします。
やったこと
ユーザーから契約アンペア数(A)と1ヶ月の使用量(kWh)を受け取って、プランごとの電気料金を返すAPIを実装
確認方法
エンドポイント
ttp://127.0.0.1:3000/api/v1/plans/all/${ampere}/${usage}の形式で実装
動作確認
30アンペア以上
30アンペア未満
無効な使用量(0未満)
無効なアンペア(10, 15, 20, 30, 40, 50, 60以外)
無効なエンドポイント