Recently I have given an interview to a widely well-known technology firm. The first interview was general and it went well but they rejected based on some technical things. They did not mention it so I expect may be due to my Coding Exercise that I submitted is not well designed.
It would be great if someone point out me my mistakes in the coding exercise. I have uploaded complete project code at git. https://github.com/aahad/Interviews/
The Coding Exercise description was:
Given a list of test results (each with a test date, Student ID, and the student’s Score), return the Final Score for each student for a user inputted date range. A student’s Final Score is calculated as the average of his/her 5 highest test scores. You can assume each student has at least 5 test scores.
We will evaluate your answer on:
- Correctness, does it work?
- Is it tested?
- Is it well designed?
- Is the code easy to comprehend?
- Would this code be easy to extend or maintain?
Your implementation must be your own, making use of your standard library. Please feel free to consult any relevant documentation.
The code works fine as per the given requirements and it does not have any issues.
I only expect that it might be possible that it is not designed well OR it could be designed in much better way, OR its not fast, scalable etc. These might be the reasons that's why got rejected.
Code
The code can also be found on https://github.com/aahad/Interviews/
Project Structure
The Controller Package (com.students.controller) has three classes:
DataLoader ( 102 lines )
package com.students.controller;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
import java.util.logging.Logger;
import com.students.model.Student;
import com.students.model.StudentTest;
import com.students.util.AppConfig;
import com.students.util.Utility;
/*
* This class is loading Student Data from a properties file via AppConfig.getStudentsDataFile()
*
*/
public class DataLoader {
private final static Logger LOGGER = Logger.getLogger(DataLoader.class .getName());
public static ArrayList<Student> loadStudentsData() {
ArrayList<Student> studentsCollection = new ArrayList<Student>(100);
try (BufferedReader br = new BufferedReader(new FileReader( AppConfig.getStudentsDataFile()) ) ) {
String recordLine = new String();
String lineItems[] = new String[3];
while ((recordLine = br.readLine()) != null) {
Student student = new Student();
StudentTest studentTest = new StudentTest();
lineItems = recordLine.split(",") ;
System.out.println( lineItems[0] + " " + lineItems[1] + " " + lineItems[2] );
student.setStudentID( Integer.parseInt(lineItems[1]) ); // second item is ID
int index ;
if ( (index = studentsCollection.indexOf(student) ) > -1 ) {
student = studentsCollection.get(index);
}
studentTest.setTestDate( Utility.convertStringIntoDate( lineItems[0] ) ); // first item is Date
studentTest.setTestScore( Float.parseFloat(lineItems[2] ) ); // first item is Score
student.addStudentTest(studentTest);
if ( index == -1) {
studentsCollection.add(student);
}
}
} catch (IOException e) {
LOGGER.warning( e.getMessage() );
}
return studentsCollection;
}
public static String[] getStudentRecordInParts(String record) {
if (record == null || record.length() < 1 )
throw new IllegalArgumentException("");
String items[] = new String[3];
int index =0;
StringBuffer item =new StringBuffer();
for(int i=0; i < record.length() ; i++ ) { //one record looks like 10-04-2014,1,60
if (record.charAt(i) != ',') {
item.append( record.charAt(i) );
}else {
items[index] = item.toString() ; //add into array
item.delete(0, item.length()); //clear previous item
index++;
}
}
if (item.length() > -1 ) { //Add last item into array
items[index] = item.toString() ;
}
//LOGGER.info(items.toString());
return items;
}
}
DateSearchController class ( 41 lines )
package com.students.controller;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.TreeSet;
import com.students.model.Student;
import com.students.model.StudentTest;
/*
* This class works as a controller to search records by date and populate Search Results collection
*
*/
public class DateSearchController {
public static TreeSet<SearchResult> searchStudentScore( Date frmDate, Date toDate) {
ArrayList<Student> students = DataLoader.loadStudentsData();
TreeSet<SearchResult> results =new TreeSet<SearchResult>() ;
for(Iterator<Student> iterator = students.iterator() ; iterator.hasNext(); ) {
Student st = iterator.next();
SearchResult rs =new SearchResult();
for( Iterator<StudentTest> testItrator = st.getStudentTestsCollection().iterator(); testItrator.hasNext(); ) {
StudentTest stest = testItrator.next();
if ( stest.getTestDate().compareTo(frmDate ) >=0 && stest.getTestDate().compareTo(toDate) <= 0 ) {
rs.setStudentID(st.getStudentID());
rs.addScore( stest.getTestScore() );
}
}
results.add(rs);
}
return results;
}
}
SearchResult class ( 71 lines )
package com.students.controller;
import java.util.TreeSet;
/*
* This class will hold all results score and will return final score
*
*/
public class SearchResult implements Comparable{
private int student;
private TreeSet<Double> scores = new TreeSet<Double>();
public void setStudentID(int student) {
this.student = student;
}
public int getStudentID() {
return this.student ;
}
public double getFinalScore() {
Object[] arr = scores.toArray();
double finalScore = 0;
int index = 0;
for(int i=arr.length - 1; i >= 0; i--) {
finalScore += (double)arr[i];
index++;
if( index == 5 ) break;
}
return finalScore / index;//
}
public void addScore(double dl) {
scores.add(dl);
}
@Override
public String toString() {
return this.student + " - " + getFinalScore();
}
@Override
public boolean equals(Object v) {
return this.student == ((SearchResult)v).student ;
}
@Override
public int hashCode() {
int hash = 5;
hash = 89 + hash + (this.scores != null ? this.scores.hashCode() : 0);
hash += 89 + hash + this.student;
return hash;
}
@Override
public int compareTo(Object v) {
return (this.student - ((SearchResult)v).student);
}
}
The Model Package (com.students.model) contains two classes:
Student class (50 lines)
package com.students.model;
import java.util.ArrayList;
import java.util.TreeSet;
/*
* This is the main student class to hold each record entry
*
*/
public class Student {
private int studentID;
private ArrayList<StudentTest> testsCollections ;
public Student() {
testsCollections = new ArrayList<StudentTest>();
}
public void setStudentID(int id) {
this.studentID = id;
}
public int getStudentID() {
return this.studentID ;
}
public void addStudentTest(StudentTest test) {
this.testsCollections.add(test);
}
public ArrayList<StudentTest> getStudentTestsCollection() {
return this.testsCollections ;
}
@Override
public boolean equals(Object v) {
return this.studentID == ((Student)v).studentID ;
}
@Override
public int hashCode() {
int hash = 5;
hash = 89 + hash + (this.testsCollections != null ? this.testsCollections.hashCode() : 0);
hash += 89 + hash + this.studentID;
return hash;
}
}
StudentTest class (31 lines )
package com.students.model;
import java.util.Date;
import java.util.TreeSet;
/*
* This student Test class hold record details by date and score
*
*/
public class StudentTest {
private Date date;
private double score;
public void setTestDate(Date date) {
this.date = date;
}
public Date getTestDate() {
return this.date ;
}
public void setTestScore(double score) {
this.score = score;
}
public double getTestScore() {
return this.score ;
}
}
The View Package (com.students.view) contains only one class:
Command class (29 lines)
package com.students.view;
import java.util.Iterator;
import java.util.TreeSet;
import com.students.controller.DateSearchController;
import com.students.controller.SearchResult;
import com.students.util.AppConfig;
/*
* Here is the main Class with main method , it is just going to search all loaded recorded and show final results
*
*/
public class Command {
public static void main(String[] arg) {
TreeSet<SearchResult> sr = DateSearchController.searchStudentScore( AppConfig.getFromDate(), AppConfig.getToDate());
for(Iterator<SearchResult> it = sr.iterator(); it.hasNext();) {
SearchResult st = it.next();
System.out.println( st );
}
}
}
The Util Package (com.students.util) contains two classes:
AppConfig class (55 lines)
package com.students.util;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Date;
import java.util.Properties;
import java.util.logging.Logger;
/*
* This class loads Application configuration details form properties file
*
*/
public class AppConfig {
public static final Properties prop = new Properties();
private static AppConfig appConfig;
private final static Logger LOGGER = Logger.getLogger(AppConfig.class .getName());
static {
getInstance();
}
private AppConfig() {
try (InputStream appConfig= new FileInputStream("config.properties") ) {
// load properties
prop.load(appConfig );
} catch (IOException io) {
io.printStackTrace();
}
}
public static synchronized AppConfig getInstance() {
if (appConfig == null) {
appConfig = new AppConfig();
}
LOGGER.info("loaded instance");
return appConfig;
}
public static String getStudentsDataFile() {
return prop.getProperty("filepath");
}
public static Date getFromDate() {
return Utility.convertStringIntoDate( prop.getProperty("FromDate") );
}
public static Date getToDate() {
return Utility.convertStringIntoDate( prop.getProperty("ToDate") );
}
}
Utility class (27 lines)
package com.students.util;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.logging.Logger;
public class Utility {
private final static DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd");
private final static Logger LOGGER = Logger.getLogger(Utility.class .getName());
public static Date convertStringIntoDate(String date) {
Date dt= new Date();
try{
dt = formatter.parse(date);
}catch(ParseException e){
LOGGER.info("Exam Date format Exception: " + e.getStackTrace() ) ;
}
return dt;
}
}
The project has one configuration (config.properties) file that has three things:
The path and name of a data file that contains students records that will be processed in the application and will be shown as per requirements i.e.
Given a list of test results (each with a test date, Student ID, and the student’s Score), return the Final Score for each student for a user inputted date range. A student’s Final Score is calculated as the average of his/her 5 highest test scores. You can assume each student has at least 5 test scores.
From Date
- To Date
The students data is saved in a CVS file under data folder inside the project and its path is set in the config.properties file. Data file can be placed on any path but config.properties path needs to be pointed out correctly.
Each student record will look like ( YYYY-MM-DD , StudentID , Exam Score )
ArrayList
as a type, but only use the interfaceList
. Similarly, useSet
as a type instead ofTreeSet
etc. \$\endgroup\$