-
Notifications
You must be signed in to change notification settings - Fork 15
Credit card validator 66 #11
base: master
Are you sure you want to change the base?
Credit card validator 66 #11
Conversation
…tion-of-candidates-task More thorough description of candidate's task
…-description Added straightforward task description
…iption-of-the-task-update Updated straightforward description of the task
General comments:
The code submitted is simply a command-line tool. Switch to commonly used frameworks. Suggesting spring boot, since it is widespread over the world and you will find lots of q'n'a s over the internet about it with quality samples. If you want a neat "menu" like in the main() routine, you may extend spring boot with additional lib such as swagger which generates a gui for rest services.
Package naming is out of the convention. Please put com.worldremit.validator as a base, then use sub packages for appropriate project components. Place code in src/main/java (You may consider some more up to date than junit - suggesting spock + groovy, which will make the test more readable, actual code docummentation and declarative src/test/groovy) Instead of ide specific files, use project files for maven (pom.xml) or prefferably more up-to-date build tool "gradle". (the later escpecially if you want to use spring boot).
For details refer subsequent comments. |
@@ -0,0 +1,7 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> |
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.
remove this file from the repo (ide specific)
@@ -0,0 +1,23 @@ | |||
# Compiled class file |
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.
Regenerate git ignore policies using a good ide (suggested - intellij). You may also want to search the internet for good samples.
@@ -0,0 +1,17 @@ | |||
<?xml version="1.0" encoding="UTF-8"?> |
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 be removed from repo
@@ -0,0 +1,11 @@ | |||
eclipse.preferences.version=1 |
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.
remove from repo (again git sanitization)
@@ -0,0 +1,5 @@ | |||
package 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.
This interface is redundant. It is a bad practice to make an interface while there is only a single implementation. (Performance reasons (enforced virtual method tables = extra work for jit), and simply unnecessary lines of code to maintain).
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.
This interface can be removed. Gives nothing.
@@ -0,0 +1,62 @@ | |||
package 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.
Move to com.worldremit.validator package. Optionally you can create also "service" subpackage.
return result; | ||
} | ||
|
||
} |
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.
Run auto-formatter on this file from your ide; automatically tidy up spaces, indents etc.
|
||
import java.util.ArrayList; | ||
|
||
public class CreditCardValidator implements CreditCardChecking { |
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.
Suggesting to redesign this class to a service:
- Rename this class to CreditCardValidatorService, drop the redundant interface as stated earlier.
- Add and inject credit card vendor name to credit card verification map ex: 'private final Map<String, CreditCardVendor> vendors;'
- The service will have a single public responsibility: 'public boolean public boolean checkValidity(String vendorName, String number) throws IllegalArgumentException'. (Should throw on unknown vendor name)
public class CreditCardValidator implements CreditCardChecking { | ||
|
||
@Override | ||
public boolean checkValidity(CreditCardVendor ccv, String number) { |
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.
This would become private. Could be called if the public method had found the vendor by name. @OverRide obviously to be dropped.
|
||
@Override | ||
public boolean checkValidity(CreditCardVendor ccv, String number) { | ||
ArrayList<Integer> chars = ccv.getNumberOfChars(); |
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.
Specific type should be only used explicitly if it states its exact purpose. Otherwise use base interfaces (Example: like sorted entries in TreeMap vs Map). These 2 can be simply Lists<> or Collections<>
ArrayList<Integer> chars = ccv.getNumberOfChars(); | ||
ArrayList<String> masks = ccv.getIIN(); | ||
|
||
boolean result1 = checkLengthCorrectness(number, chars); |
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.
These 3 booleans should be named more precisely if they stay. (ex lengthCorrect).
Their existence is actually redundant unless you want to debug the code and step over. In other cases this code will benefit on performance if rewritten to return checkLengthCorrectness(...) && checkIINMaskCorrectness(...) && checkLuhnalgorithmCorrectness(...);
Java && operator evaluation will save us from unnecessary calls and evaluations if we fail earlyin the chain.
return result1 && result2 && result3; | ||
} | ||
|
||
private boolean checkLengthCorrectness(String number, ArrayList<Integer> chars){ |
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.
List instead of ArrayList (see prev comments)
return result; | ||
} | ||
|
||
private boolean checkIINMaskCorrectness (String number, ArrayList<String> masks){ |
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.
List<>
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.
Same comments as in the previous routine.
private boolean checkLengthCorrectness(String number, ArrayList<Integer> chars){ | ||
boolean result = false; | ||
for (int i = 0; i<chars.size();i++){ | ||
if (chars.get(i) == number.length()) |
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.
Bail out here with return false if not equal; performance
Refactor to : (do not leave code branches without bracketed scopes - potential risk of logic breaking by mistake or some code merges.
if () {
return false;
}
} | ||
|
||
private boolean checkLengthCorrectness(String number, ArrayList<Integer> chars){ | ||
boolean result = false; |
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.
reduntant flag
if (chars.get(i) == number.length()) | ||
result = true; | ||
} | ||
return result; |
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.
return true
@@ -0,0 +1,7 @@ | |||
package 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.
Another redundant interface (see prev comments). Can be removed from the project.
|
||
import java.util.ArrayList; | ||
|
||
public class CreditCardVendor { |
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.
This class should have a better name for what it does. CreditCartVendorParameter perhaps?
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.
If using a new java, use java record. Otherwise, this class should be final/immutable.
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.
Preferably factorize all lists with immutable utils from guava
|
||
return result1 && result2 && result3; | ||
} | ||
|
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.
The following functions can be extracted to another util class and made public statics perhaps. Suggesting com.worldremit.validator.utils.CCVUtils.
@@ -0,0 +1,60 @@ | |||
package 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.
move to com.worldremit.validator
import java.io.InputStreamReader; | ||
import java.util.ArrayList; | ||
|
||
public class CreditCardValidatorProject { |
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.
Redesign to a spring boot application starter. Use swagger for "browser gui / menu"
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.
Rename to CreditCardValidatorAppRunner
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.
Create RestController class which would call upon the CreaditCallValidatorService with the recived request. https://spring.io/guides/tutorials/rest/
Inject the service to that controller.
Create configuration class which will create other beans - CreditCardService, and VendorsLoader and Maping (As mentioned in the serice class)
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.
import java.util.ArrayList; | ||
|
||
public class CreditCardVendor { | ||
private String name; |
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.
final
|
||
public class CreditCardVendor { | ||
private String name; | ||
private ArrayList<Integer> numberOfChars; |
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.
can change to private final int[] - will be easier on gc. linear memory, no autoboxing (simply performacne)
public class CreditCardVendor { | ||
private String name; | ||
private ArrayList<Integer> numberOfChars; | ||
private ArrayList<String> IIN; |
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.
private final List
return IIN; | ||
} | ||
|
||
public CreditCardVendor(String vendorName, ArrayList<Integer> charsNumbers, ArrayList<String> masks){ |
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.
stor shoulb be before public methods, after fields.
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.
Optionally, lines with more than 2 parameters can be restructured to 1 line - param mode. easier to compare on diffs, prs, better reflection of data structure which the class represents
IIN = masks; | ||
} | ||
|
||
@Override |
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.
Optionally generate == and # code contracts using ide
@@ -0,0 +1,55 @@ | |||
package 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.
move to appropriate package and tests directory.
|
||
import org.junit.Test; | ||
|
||
public class Tests { |
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.
Rename and split into individual test classes associated with parentcode. Ex CreditCardValidatorServiceTest, CreditCardUtilsTest
|
||
@Test | ||
public void testLengthOfNumberWhenCorrect() { | ||
String number = "5584239583699571"; |
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.
write the test having "Given" "When" "Then" declarative approach. Ex:
@Test
public void testLengthOfNumberWhenIncorrect() {
//Given
String number = "55842395";
//When
var result = validator.checkValidity(vendorMasterCard, number);
//Then
assertFalse(result);
}
@Test | ||
public void testLengthOfNumberWhenIncorrect() { | ||
String number = "55842395"; | ||
assertEquals(false, validator.checkValidity(vendorMasterCard, number)); |
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.
use assertTrue/assertFalse for clean looks
@@ -0,0 +1,58 @@ | |||
package 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.
move to com.worldremit.validator.utils package.
import java.io.IOException; | ||
import java.util.ArrayList; | ||
|
||
public class CreditCardVendorsReader implements CreditCardVendorReading { |
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.
Rename to CreditCartVendorParameterLoader, use in the spring configuration bean to load the map of venrods
return result; | ||
} | ||
|
||
private boolean checkLuhnalgorithmCorrectness(String number){ |
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.
function name casing is wrong - checkLuhnAlgorithmCorrectness
private boolean checkLuhnalgorithmCorrectness(String number){ | ||
boolean result = false; | ||
|
||
String[] characters = number.split(""); |
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.
gnerally inefficient and messy code. It would be easier to rely on this https://gist.github.com/mdp/9691528
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.
(digit parsing is extremely inefficient here, readability of code is also poor)
|
||
public class CreditCardVendorsReader implements CreditCardVendorReading { | ||
@Override | ||
public ArrayList<CreditCardVendor> returnVendorArray() { |
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.
return Map<String, CCVPArameters> here, rename to loadVendors()
list.add(new CreditCardVendor(vendorName,vendorNumbersOfChars,vendorMasks)); | ||
|
||
} | ||
} catch (FileNotFoundException e) { |
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.
should not consume exceptions during app startup. log the exception and rethrow, the framework will handle rest
} | ||
} | ||
|
||
} |
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.
run formatter on this file
private void parseMasks(String value, ArrayList<String> vendorMasks){ | ||
String[] masks = value.split("/"); | ||
for(int i=0;i<masks.length; i++){ | ||
if (masks[i].split("-").length == 1){ |
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.
inefficient code, do split once, remember it in a var
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.
Apart from the previous comments, this code to be prod ready should use some logging in importat places - incoming requests, data construction, results etc.
Also,application and jvm metrics should be collected and exposed to company's infrastructure. As the first MVP phase to accepted to go live
@@ -0,0 +1,2 @@ | |||
Visa 13/16 4 |
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.
This file should be moved to resources, and accessed via LoadResource functions for MVP phase.
Eventually, the app setup should load this from your company's config server infrastructure via spring utils
marcin kapolka