Before you go, check out these stories!

0
Hackernoon logoLeetcode Coding Challenge Using Lambda by@hariohmprasath

Leetcode Coding Challenge Using Lambda

Author profile picture

@hariohmprasathHari Ohm Prasath

https://www.linkedin.com/in/hariohmprasath/

I am a big fan of leet code so when we decided to have a code challenge in our team I thought it wouldn’t be a bad idea to build one which should include pretty basic functionalities like:

  • Ability to register and sign in to the application
  • Present the problem (questions)
  • Provide an interface for the end-users to write, compile and execute code.

Overall, it was an amazing learning experience and I am happy to walk through how I did it.

Guidelines

Before I start working on this I decided to come up with some guidelines so I don't over-engineer this and end up building a Frankenstein out of it, here are few of those guidelines:

  • The whole system should be implemented in 3 to 4 days
  • Reuse as much as you can when it comes to technology or service. DON'T build anything new unless until it doesn't exist
  • ZERO standing cost for the infrastructure. Pay ONLY for what you use and pay as MINIMAL you can

Technologies & Runtime Services

  • Bootstrap + JQuery (UI)
  • AWS Lambda
  • AWS API Gateway
  • AWS Dynamodb
  • AWS Dynamodb streams
  • AWS Simple email service (SES)
  • AWS S3 (For static site hosting)


High-level Architecture

The system consists of four keys functionalities based on which these modules are designed:

  • Registration & sign-in
  • Compile & Execute
  • Score Calculator
  • Winner Predictor

Registration & Sign-in Flow

We have a single lambda function that takes care of registering a new user
and authenticating an existing user in the application.

  • Part of registration flow user enters “FirstName”, “LastName” & “Email
    address” which is passed in as “QueryParam” to API gateway. Gateway
    invokes a Lambda function which takes care of saving the user details in
    DynamoDb, generating a random registration code (UUID based) and
    sending it in an email to the registered email address
  • The sign-in flow will authenticate the user with the passed in email address and UUID using the Lambda function

Compile & Execute

When the user submits the code, the web application will call the API gateway with the following parameters:

  • QuestionsId
  • User types code
  • Registration code

API gateway will invoke the lambda function which will get information
about the question/problem statement from the “Questions” table in
Dynamodb (data looks like below).

From the table data, we take the “GeneratedCode” attribute value and
replace various tokens like — name — , — codeworking — & — testcases
— with the class name (generated), the user typed code, and test cases
(from columns “Test_1”… “Test_N”). Here is how the replaced code will
look:

// --name--
public class f_sdsds_a11223_dd {
    
    // --codeworking--
    static class Solution{
      public static int calculate(String s){
       int count=0;
       int index=0;
          while(true){
              try{
                  s.charAt(index++);
                  count++;
              }catch(Exception e){
                  break;
              }
          }         
          return count;
      }
   }
public static void main(String args[]) {        
        int actual=0;
        int expected = 3;
        String input = null;
        // --testcases--       
        input = "Hi1";
        expected = 3;
        actual = Solution.calculate(input);        
        assert actual == expected :  String.format("--helper-- Input %s -> Expected = %s but got = %s", input, expected, actual);
    }
}

Since Lambda containers don't have JDK installed we have to package
“tools.jar” inside the deployment package so we can run the compilation
inside the containers, here is the code snippet on how we run compile
inside lambda:

try (StringInputStream inputStream = new StringInputStream(data);
     ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
     ByteArrayOutputStream errorOutputStream = new ByteArrayOutputStream()) {
    Class<?> javacTool = Class.forName("com.sun.tools.javac.api.JavacTool");
    Method create = javacTool.getMethod("create");
    JavaCompiler compiler = (JavaCompiler) create.invoke(null);
    compiler.run(inputStream, outputStream, errorOutputStream, path.toFile().getAbsolutePath());
    return new ProcessResponse(replaceNewLine(outputStream), replaceNewLine(errorOutputStream));
} catch (Exception e) {
    return new ProcessResponse(null, "Compilation error --> " + e.getMessage());
}

If compilation is successful, we run the generated class which contains the test cases.

java -ea -cp /tmp/f_sdsds_a11223_dd 

If execution is successful without any assertion failures, execution time is stored in “UserSubmission” table.

Score Calculator

We utilize DynamoDB streams to update the total points and total execution time for any given user. A lambda function listens to all updates done on “UserSubmission” table and performs these calculations once the
submission is successful.

Winner Predictor

To find the winners, we run a simple query to get the top 3 rows in
“UserStastics” table generated by sorting “TotalPoints” column in
descending order and “TotalExecution” column in ascending

Demo

Here is the demo of the application:

I know this doesn't solve all the use cases that a popular code challenge websites like “leetcode” or “topcoder” solves. But this is a good start & foundation which we can keep adding on.

If you like this post then leave a comment. That way, I know you have made it all the way to the end 😀 . Thanks again for reading.

Previously published at https://medium.com/javarevisited/build-code-challenge-application-23aa40d183fa

Tags

Become a Hackolyte

Level up your reading game by joining Hacker Noon now!