Simple OOP currency converterSimple OOP currency converter - follow-upIntroductory Currency ConverterCurrency converter in PythonCurrency converter in Python 2.7Currency converter built with AngularJSSimple temperature converter in CCurrency Converter in Python 3Simple unit converter and shipment builderChangeCalculator for calculating money denominations in changeCurrency converter - CLI and APITemperature and currency converters in OOP JS

How are mathematicians paid to do research?

Do I have a right to cancel a purchase of foreign currency in the UK?

Should disabled buttons give feedback when clicked?

Why does wrapping aluminium foil around my food help it keep warm, even though aluminium is a good conductor?

What's the point of having a RAID 1 configuration over incremental backups to a secondary drive?

Is Trump personally blocking people on Twitter?

Astronaut distance from Earth?

Why didn't Thanos kill all the Dwarves on Nidavellir?

What specific instant in time in the MCU has been depicted the most times?

Does Multiverse exist in MCU?

Is English unusual in having no second person plural form?

Using `PlotLegends` with a `ColorFunction`

Can the Mage Hand cantrip be used to trip an enemy who is running away?

Salt, pepper, herbs and spices

How quality assurance engineers test calculations?

Print the last, middle and first character of your code

Graduate student with abysmal English writing skills, how to help

Why weren't bootable game disks ever common on the IBM PC?

Would a non-attacking Barbarian's rage end the same turn he started it?

Received a dinner invitation through my employer's email, is it ok to attend?

LED glows slightly during soldering

How to disable constructors in custom exceptions?

What is this little owl-like bird?

Would dual wielding daggers be a viable choice for a covert bodyguard?



Simple OOP currency converter


Simple OOP currency converter - follow-upIntroductory Currency ConverterCurrency converter in PythonCurrency converter in Python 2.7Currency converter built with AngularJSSimple temperature converter in CCurrency Converter in Python 3Simple unit converter and shipment builderChangeCalculator for calculating money denominations in changeCurrency converter - CLI and APITemperature and currency converters in OOP JS






.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty margin-bottom:0;








7












$begingroup$


I am learning about OOP so it would be great if you can give me feedback on how to improve my code and OOP design.



This is a currency converter. Firstly, it will call a method to add 2 currencies and commission information and then it converts to another currency whose input is source currency and amount:



import pytest


class Bank:

def addRate(self,first, second, rate):
self.first_currency = first
self.second_currency = second
self.rate = rate

def addCommission(self,commision):
self.commission = commision


def convert(self, currency, amount):
if currency == self.first_currency:
return (amount / self.rate) * (1-self.commission)
else:
return (amount * self.rate) * (1-self.commission)

@pytest.fixture()
def bank():
return Bank()

def test_Bank_addRate(bank):

bank.addRate("USD","GBP",2)
assert bank.first_currency == "USD"
assert bank.second_currency == "GBP"
assert bank.rate == 2

def test_Bank_addCommision(bank):
bank.addCommission(0.015)
assert bank.commission == 0.015


def test_Bank_convert(bank):
bank.addRate("USD", "GBP", 2)
bank.addCommission(0.015)
assert bank.convert("USD", 100) == 49.25









share|improve this question











$endgroup$







  • 5




    $begingroup$
    Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
    $endgroup$
    – juhist
    Jul 2 at 13:12






  • 1




    $begingroup$
    Your code defines a Currency class but it doesn’t seem to be using it — what is its purpose?
    $endgroup$
    – Konrad Rudolph
    Jul 2 at 13:14










  • $begingroup$
    @KonradRudolph, thank you. I removed it
    $endgroup$
    – Nguyen
    Jul 2 at 16:02











  • $begingroup$
    @juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
    $endgroup$
    – Nguyen
    Jul 2 at 16:04






  • 2




    $begingroup$
    Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
    $endgroup$
    – Sᴀᴍ Onᴇᴌᴀ
    Jul 2 at 16:08

















7












$begingroup$


I am learning about OOP so it would be great if you can give me feedback on how to improve my code and OOP design.



This is a currency converter. Firstly, it will call a method to add 2 currencies and commission information and then it converts to another currency whose input is source currency and amount:



import pytest


class Bank:

def addRate(self,first, second, rate):
self.first_currency = first
self.second_currency = second
self.rate = rate

def addCommission(self,commision):
self.commission = commision


def convert(self, currency, amount):
if currency == self.first_currency:
return (amount / self.rate) * (1-self.commission)
else:
return (amount * self.rate) * (1-self.commission)

@pytest.fixture()
def bank():
return Bank()

def test_Bank_addRate(bank):

bank.addRate("USD","GBP",2)
assert bank.first_currency == "USD"
assert bank.second_currency == "GBP"
assert bank.rate == 2

def test_Bank_addCommision(bank):
bank.addCommission(0.015)
assert bank.commission == 0.015


def test_Bank_convert(bank):
bank.addRate("USD", "GBP", 2)
bank.addCommission(0.015)
assert bank.convert("USD", 100) == 49.25









share|improve this question











$endgroup$







  • 5




    $begingroup$
    Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
    $endgroup$
    – juhist
    Jul 2 at 13:12






  • 1




    $begingroup$
    Your code defines a Currency class but it doesn’t seem to be using it — what is its purpose?
    $endgroup$
    – Konrad Rudolph
    Jul 2 at 13:14










  • $begingroup$
    @KonradRudolph, thank you. I removed it
    $endgroup$
    – Nguyen
    Jul 2 at 16:02











  • $begingroup$
    @juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
    $endgroup$
    – Nguyen
    Jul 2 at 16:04






  • 2




    $begingroup$
    Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
    $endgroup$
    – Sᴀᴍ Onᴇᴌᴀ
    Jul 2 at 16:08













7












7








7


1



$begingroup$


I am learning about OOP so it would be great if you can give me feedback on how to improve my code and OOP design.



This is a currency converter. Firstly, it will call a method to add 2 currencies and commission information and then it converts to another currency whose input is source currency and amount:



import pytest


class Bank:

def addRate(self,first, second, rate):
self.first_currency = first
self.second_currency = second
self.rate = rate

def addCommission(self,commision):
self.commission = commision


def convert(self, currency, amount):
if currency == self.first_currency:
return (amount / self.rate) * (1-self.commission)
else:
return (amount * self.rate) * (1-self.commission)

@pytest.fixture()
def bank():
return Bank()

def test_Bank_addRate(bank):

bank.addRate("USD","GBP",2)
assert bank.first_currency == "USD"
assert bank.second_currency == "GBP"
assert bank.rate == 2

def test_Bank_addCommision(bank):
bank.addCommission(0.015)
assert bank.commission == 0.015


def test_Bank_convert(bank):
bank.addRate("USD", "GBP", 2)
bank.addCommission(0.015)
assert bank.convert("USD", 100) == 49.25









share|improve this question











$endgroup$




I am learning about OOP so it would be great if you can give me feedback on how to improve my code and OOP design.



This is a currency converter. Firstly, it will call a method to add 2 currencies and commission information and then it converts to another currency whose input is source currency and amount:



import pytest


class Bank:

def addRate(self,first, second, rate):
self.first_currency = first
self.second_currency = second
self.rate = rate

def addCommission(self,commision):
self.commission = commision


def convert(self, currency, amount):
if currency == self.first_currency:
return (amount / self.rate) * (1-self.commission)
else:
return (amount * self.rate) * (1-self.commission)

@pytest.fixture()
def bank():
return Bank()

def test_Bank_addRate(bank):

bank.addRate("USD","GBP",2)
assert bank.first_currency == "USD"
assert bank.second_currency == "GBP"
assert bank.rate == 2

def test_Bank_addCommision(bank):
bank.addCommission(0.015)
assert bank.commission == 0.015


def test_Bank_convert(bank):
bank.addRate("USD", "GBP", 2)
bank.addCommission(0.015)
assert bank.convert("USD", 100) == 49.25






python beginner object-oriented unit-conversion






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Jul 2 at 16:01







Nguyen

















asked Jul 2 at 1:31









NguyenNguyen

555 bronze badges




555 bronze badges







  • 5




    $begingroup$
    Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
    $endgroup$
    – juhist
    Jul 2 at 13:12






  • 1




    $begingroup$
    Your code defines a Currency class but it doesn’t seem to be using it — what is its purpose?
    $endgroup$
    – Konrad Rudolph
    Jul 2 at 13:14










  • $begingroup$
    @KonradRudolph, thank you. I removed it
    $endgroup$
    – Nguyen
    Jul 2 at 16:02











  • $begingroup$
    @juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
    $endgroup$
    – Nguyen
    Jul 2 at 16:04






  • 2




    $begingroup$
    Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
    $endgroup$
    – Sᴀᴍ Onᴇᴌᴀ
    Jul 2 at 16:08












  • 5




    $begingroup$
    Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
    $endgroup$
    – juhist
    Jul 2 at 13:12






  • 1




    $begingroup$
    Your code defines a Currency class but it doesn’t seem to be using it — what is its purpose?
    $endgroup$
    – Konrad Rudolph
    Jul 2 at 13:14










  • $begingroup$
    @KonradRudolph, thank you. I removed it
    $endgroup$
    – Nguyen
    Jul 2 at 16:02











  • $begingroup$
    @juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
    $endgroup$
    – Nguyen
    Jul 2 at 16:04






  • 2




    $begingroup$
    Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
    $endgroup$
    – Sᴀᴍ Onᴇᴌᴀ
    Jul 2 at 16:08







5




5




$begingroup$
Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
$endgroup$
– juhist
Jul 2 at 13:12




$begingroup$
Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function.
$endgroup$
– juhist
Jul 2 at 13:12




1




1




$begingroup$
Your code defines a Currency class but it doesn’t seem to be using it — what is its purpose?
$endgroup$
– Konrad Rudolph
Jul 2 at 13:14




$begingroup$
Your code defines a Currency class but it doesn’t seem to be using it — what is its purpose?
$endgroup$
– Konrad Rudolph
Jul 2 at 13:14












$begingroup$
@KonradRudolph, thank you. I removed it
$endgroup$
– Nguyen
Jul 2 at 16:02





$begingroup$
@KonradRudolph, thank you. I removed it
$endgroup$
– Nguyen
Jul 2 at 16:02













$begingroup$
@juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
$endgroup$
– Nguyen
Jul 2 at 16:04




$begingroup$
@juhist Thank you for your advice. I agree but now I am learning about OOP so I want to focus on it
$endgroup$
– Nguyen
Jul 2 at 16:04




2




2




$begingroup$
Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
$endgroup$
– Sᴀᴍ Onᴇᴌᴀ
Jul 2 at 16:08




$begingroup$
Welcome to Code Review! It appears you have modified the code slightly, mostly in response to Konrad's comment above. After getting an answer you should not change your code anymore. This is to ensure that answers do not get invalidated and have to hit a moving target. If you have changed your code you can either post it as an answer (if it would constitute a code review) or ask a new question with your changed code (linking back to this one as reference). Refer to this post for more information
$endgroup$
– Sᴀᴍ Onᴇᴌᴀ
Jul 2 at 16:08










2 Answers
2






active

oldest

votes


















9












$begingroup$

First: welcome to CodeReview! I hope that you get good feedback.



About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate() can be called multiple times per single Bank instance, and that convert would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.



There are two ways to go, here. Either make your class an ExchangeRate, in which case



  • you need to rename the class


  • convert, rather than accepting the name of a currency, should perhaps accept a forward boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e. dest_currency.

  • Rename your addCommission to setCommission. "add" implies having more than one.

  • Rename your addRate to setRate. "add" implies having more than one.

Or, keep a "Bank" class, in which case:



  • you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member

  • convert would accept both a source and destination currency

  • addRate's signature would stay the same, but its contents would change to use your dict.





share|improve this answer









$endgroup$












  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19


















3












$begingroup$

There are a few smells in your code.



  1. Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.


  2. What if you want to do GBP->EUR? do you create another bank?


  3. In real life, currency exchange rates change over time. How will your bank object reflect that?

  4. Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.

  5. Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.

A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.






share|improve this answer









$endgroup$












  • $begingroup$
    Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
    $endgroup$
    – Nguyen
    Jul 3 at 0:17











  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19










  • $begingroup$
    4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
    $endgroup$
    – wallenborn
    Jul 3 at 14:50













Your Answer






StackExchange.ifUsing("editor", function ()
StackExchange.using("externalEditor", function ()
StackExchange.using("snippets", function ()
StackExchange.snippets.init();
);
);
, "code-snippets");

StackExchange.ready(function()
var channelOptions =
tags: "".split(" "),
id: "196"
;
initTagRenderer("".split(" "), "".split(" "), channelOptions);

StackExchange.using("externalEditor", function()
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled)
StackExchange.using("snippets", function()
createEditor();
);

else
createEditor();

);

function createEditor()
StackExchange.prepareEditor(
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: false,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: null,
bindNavPrevention: true,
postfix: "",
imageUploader:
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
,
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
);



);













draft saved

draft discarded


















StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f223322%2fsimple-oop-currency-converter%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown

























2 Answers
2






active

oldest

votes








2 Answers
2






active

oldest

votes









active

oldest

votes






active

oldest

votes









9












$begingroup$

First: welcome to CodeReview! I hope that you get good feedback.



About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate() can be called multiple times per single Bank instance, and that convert would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.



There are two ways to go, here. Either make your class an ExchangeRate, in which case



  • you need to rename the class


  • convert, rather than accepting the name of a currency, should perhaps accept a forward boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e. dest_currency.

  • Rename your addCommission to setCommission. "add" implies having more than one.

  • Rename your addRate to setRate. "add" implies having more than one.

Or, keep a "Bank" class, in which case:



  • you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member

  • convert would accept both a source and destination currency

  • addRate's signature would stay the same, but its contents would change to use your dict.





share|improve this answer









$endgroup$












  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19















9












$begingroup$

First: welcome to CodeReview! I hope that you get good feedback.



About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate() can be called multiple times per single Bank instance, and that convert would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.



There are two ways to go, here. Either make your class an ExchangeRate, in which case



  • you need to rename the class


  • convert, rather than accepting the name of a currency, should perhaps accept a forward boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e. dest_currency.

  • Rename your addCommission to setCommission. "add" implies having more than one.

  • Rename your addRate to setRate. "add" implies having more than one.

Or, keep a "Bank" class, in which case:



  • you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member

  • convert would accept both a source and destination currency

  • addRate's signature would stay the same, but its contents would change to use your dict.





share|improve this answer









$endgroup$












  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19













9












9








9





$begingroup$

First: welcome to CodeReview! I hope that you get good feedback.



About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate() can be called multiple times per single Bank instance, and that convert would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.



There are two ways to go, here. Either make your class an ExchangeRate, in which case



  • you need to rename the class


  • convert, rather than accepting the name of a currency, should perhaps accept a forward boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e. dest_currency.

  • Rename your addCommission to setCommission. "add" implies having more than one.

  • Rename your addRate to setRate. "add" implies having more than one.

Or, keep a "Bank" class, in which case:



  • you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member

  • convert would accept both a source and destination currency

  • addRate's signature would stay the same, but its contents would change to use your dict.





share|improve this answer









$endgroup$



First: welcome to CodeReview! I hope that you get good feedback.



About your code. Your usage of Python is not terrible; most of your problems are conceptual, about the decisions you've made about your class. Looking at the method signatures from the outside, one would guess that addRate() can be called multiple times per single Bank instance, and that convert would then allow for any currency to be converted. That isn't the case; instead, your "Bank" class is actually closer to an "ExchangeRate" class.



There are two ways to go, here. Either make your class an ExchangeRate, in which case



  • you need to rename the class


  • convert, rather than accepting the name of a currency, should perhaps accept a forward boolean. Or, if you want to keep passing the name of a currency, it's important to make the argument name more clear, i.e. dest_currency.

  • Rename your addCommission to setCommission. "add" implies having more than one.

  • Rename your addRate to setRate. "add" implies having more than one.

Or, keep a "Bank" class, in which case:



  • you need to change the way that you store your exchange rates, probably to a dictionary-based system instead of a single float member

  • convert would accept both a source and destination currency

  • addRate's signature would stay the same, but its contents would change to use your dict.






share|improve this answer












share|improve this answer



share|improve this answer










answered Jul 2 at 2:44









ReinderienReinderien

6,16610 silver badges29 bronze badges




6,16610 silver badges29 bronze badges











  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19
















  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19















$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19




$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19













3












$begingroup$

There are a few smells in your code.



  1. Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.


  2. What if you want to do GBP->EUR? do you create another bank?


  3. In real life, currency exchange rates change over time. How will your bank object reflect that?

  4. Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.

  5. Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.

A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.






share|improve this answer









$endgroup$












  • $begingroup$
    Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
    $endgroup$
    – Nguyen
    Jul 3 at 0:17











  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19










  • $begingroup$
    4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
    $endgroup$
    – wallenborn
    Jul 3 at 14:50















3












$begingroup$

There are a few smells in your code.



  1. Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.


  2. What if you want to do GBP->EUR? do you create another bank?


  3. In real life, currency exchange rates change over time. How will your bank object reflect that?

  4. Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.

  5. Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.

A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.






share|improve this answer









$endgroup$












  • $begingroup$
    Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
    $endgroup$
    – Nguyen
    Jul 3 at 0:17











  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19










  • $begingroup$
    4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
    $endgroup$
    – wallenborn
    Jul 3 at 14:50













3












3








3





$begingroup$

There are a few smells in your code.



  1. Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.


  2. What if you want to do GBP->EUR? do you create another bank?


  3. In real life, currency exchange rates change over time. How will your bank object reflect that?

  4. Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.

  5. Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.

A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.






share|improve this answer









$endgroup$



There are a few smells in your code.



  1. Currency exchange rates are usually not inverses of each other. Your code assumes that GBP / USD is one number, and that number is a property of your Bank object. That is a smell, because a. banks don't own exchange rates, and b. there should at least be a GBP->USD rate as well as the USD->GBP rate.


  2. What if you want to do GBP->EUR? do you create another bank?


  3. In real life, currency exchange rates change over time. How will your bank object reflect that?

  4. Your bank is mutable (this could be part of the answer to the question above, but then the next question is Who will change the bank if the exchange rates change?). Mutable means: when a method takes a bank as parameter, there is nothing to stop it from saying bank.addRate("RUB", "YEN", 1.71), and that would change the original object, which is a. bad, and b. in any case not what you'd expect an addRate method to do.

  5. Your code is striving for symmetry. Is that a good thing? You might have an Amount(amount, currency) class one day, and then your bank would probably be asked to bank.convertTo(amout, targetCurrency) which is distinctly not symmetric.

A typical mistake programmers new to oop often make is to model structures instead of behaviours. The tendency is to look at the bones of what you want to model, not at the muscles. Hence you come up with a Bank class, because a bank is a thing, and a Currency class, because a currency is a thing, and then it's quickly unclear what these classes actually are supposed to do. Try to think more in terms of What is being done, and less in terms of Who is doing it.







share|improve this answer












share|improve this answer



share|improve this answer










answered Jul 2 at 16:29









wallenbornwallenborn

2911 silver badge4 bronze badges




2911 silver badge4 bronze badges











  • $begingroup$
    Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
    $endgroup$
    – Nguyen
    Jul 3 at 0:17











  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19










  • $begingroup$
    4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
    $endgroup$
    – wallenborn
    Jul 3 at 14:50
















  • $begingroup$
    Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
    $endgroup$
    – Nguyen
    Jul 3 at 0:17











  • $begingroup$
    Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
    $endgroup$
    – Nguyen
    Jul 3 at 12:19










  • $begingroup$
    4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
    $endgroup$
    – wallenborn
    Jul 3 at 14:50















$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17





$begingroup$
Thank you for anwering me. Let me answer your question: 1. I will change Bank class to ExchangeRate. I will create a dictionary rate = "GBPUSD": 2, "USDGBP: 0.5 2. So you mean I should create a dictionary for rate ? So I don't have to call another ExchangeRate everytime ? 3. I think I should add method: changeRate 4. I should raise exception as soon as addRate was called 2nd time for same pair currency and add new method: changeRate() which can be called multiple time 5. I don't quite understand the point. I think I should create a class for storing currency amounts
$endgroup$
– Nguyen
Jul 3 at 0:17













$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19




$begingroup$
Hi, I re-implement my code and created follow-up question here. Can you take a look ? codereview.stackexchange.com/questions/223411/…
$endgroup$
– Nguyen
Jul 3 at 12:19












$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50




$begingroup$
4. My point is that rates change over time, so you don't want them to be constant, but clients should not be allowed to change them, so you want them to be immutable. Think about how to solve this.
$endgroup$
– wallenborn
Jul 3 at 14:50

















draft saved

draft discarded
















































Thanks for contributing an answer to Code Review Stack Exchange!


  • Please be sure to answer the question. Provide details and share your research!

But avoid


  • Asking for help, clarification, or responding to other answers.

  • Making statements based on opinion; back them up with references or personal experience.

Use MathJax to format equations. MathJax reference.


To learn more, see our tips on writing great answers.




draft saved


draft discarded














StackExchange.ready(
function ()
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f223322%2fsimple-oop-currency-converter%23new-answer', 'question_page');

);

Post as a guest















Required, but never shown





















































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown

































Required, but never shown














Required, but never shown












Required, but never shown







Required, but never shown







Popular posts from this blog

Get product attribute by attribute group code in magento 2get product attribute by product attribute group in magento 2Magento 2 Log Bundle Product Data in List Page?How to get all product attribute of a attribute group of Default attribute set?Magento 2.1 Create a filter in the product grid by new attributeMagento 2 : Get Product Attribute values By GroupMagento 2 How to get all existing values for one attributeMagento 2 get custom attribute of a single product inside a pluginMagento 2.3 How to get all the Multi Source Inventory (MSI) locations collection in custom module?Magento2: how to develop rest API to get new productsGet product attribute by attribute group code ( [attribute_group_code] ) in magento 2

Category:9 (number) SubcategoriesMedia in category "9 (number)"Navigation menuUpload mediaGND ID: 4485639-8Library of Congress authority ID: sh85091979ReasonatorScholiaStatistics

Magento 2.3: How do i solve this, Not registered handle, on custom form?How can i rewrite TierPrice Block in Magento2magento 2 captcha not rendering if I override layout xmlmain.CRITICAL: Plugin class doesn't existMagento 2 : Problem while adding custom button order view page?Magento 2.2.5: Overriding Admin Controller sales/orderMagento 2.2.5: Add, Update and Delete existing products Custom OptionsMagento 2.3 : File Upload issue in UI Component FormMagento2 Not registered handleHow to configured Form Builder Js in my custom magento 2.3.0 module?Magento 2.3. How to create image upload field in an admin form