Skip to content
This repository has been archived by the owner on Jul 14, 2023. It is now read-only.

Credit card validator 66 #11

Open
wants to merge 10 commits into
base: master
Choose a base branch
from

Conversation

marcin-kapolka-prv
Copy link

marcin kapolka

@marcin-kapolka-prv
Copy link
Author

General comments:

  1. The requirement of creating a rest service is not satisfied.

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.

  1. General java project and coding guidelines were not followed.

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
Place tests in src/test/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).

  1. Git repository best practices were broken.
  • ide specific files committed
  • most probably a random gitingnore file uploaded. Please check your ide/github options to generate a valid file for specified language + ide composition.
  1. Forget about eclipse ide :) get a real contemporary ide for jvm languages. It will save you a lot of effort and time. - follow hints from it :)

For details refer subsequent comments.

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
Copy link
Author

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
Copy link
Author

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"?>
Copy link
Author

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
Copy link
Author

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;
Copy link
Author

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).

Copy link
Author

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;
Copy link
Author

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;
}

}
Copy link
Author

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 {
Copy link
Author

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) {
Copy link
Author

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();
Copy link
Author

@marcin-kapolka-prv marcin-kapolka-prv Feb 7, 2021

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);
Copy link
Author

@marcin-kapolka-prv marcin-kapolka-prv Feb 7, 2021

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){
Copy link
Author

@marcin-kapolka-prv marcin-kapolka-prv Feb 7, 2021

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){
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

List<>

Copy link
Author

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())
Copy link
Author

@marcin-kapolka-prv marcin-kapolka-prv Feb 7, 2021

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;
Copy link
Author

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;
Copy link
Author

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;
Copy link
Author

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 {
Copy link
Author

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?

Copy link
Author

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.

Copy link
Author

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;
}

Copy link
Author

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;
Copy link
Author

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 {
Copy link
Author

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"

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rename to CreditCardValidatorAppRunner

Copy link
Author

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)

Copy link
Author

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;
Copy link
Author

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;
Copy link
Author

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;
Copy link
Author

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){
Copy link
Author

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.

Copy link
Author

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
Copy link
Author

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;
Copy link
Author

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 {
Copy link
Author

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";
Copy link
Author

@marcin-kapolka-prv marcin-kapolka-prv Feb 7, 2021

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));
Copy link
Author

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;
Copy link
Author

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 {
Copy link
Author

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){
Copy link
Author

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("");
Copy link
Author

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

Copy link
Author

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() {
Copy link
Author

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) {
Copy link
Author

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

}
}

}
Copy link
Author

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){
Copy link
Author

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

Copy link
Author

@marcin-kapolka-prv marcin-kapolka-prv left a 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
Copy link
Author

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

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants