Interview Questions
===
Java
---
### What's the different between == and hash in Java?
== is just an identity check. To compare if the two variables are pointing to the same object (i.e., have the same reference in memory).
hash is value returned from the hashCode() method of the object.
if == returns true, the two variables are referencing the same object, thus their hash are the same.
if == returns false, the two variables are referencing two different objects, their hash could be the same or could be different. Depending on the calculation implemented in the hashCode() method.
More usual question, instead, is what's the difference between equals() method and hashCode() method? And ...
#### What's the difference between == and equals()?
== checks if the two variables are referencing the same object. It's a reference/identity check (i.e., if the two points the same memory location).
equals() checks if the two variables have the same value. It's a value check. Two values in different object could be logically the same/equal. What equal mean is based on what you implement in equals() method.
#### What are the rules to follow when implementing hashCode()?
The easiest is to generate the code in tool like Eclipse.
Essentially, it is desirable to generate some equally distributed set of values for objects in a collection.
The worst way to implement hashCode() is to always return the same value. When implemented this way and when the objects are used as key in a map or set, put/get operations on the the map/set will be very inefficient. All objects are in the same list internally in the map/set. Operations on the map/set are essentially sequential.
#### How does map work? How are hashCode() and equals() methods related to map/set? What happens when you call a put() method on a map/set? What happens when you call a get() method on a map/set?
Map is a container that stores a pair of data, a key and an associated value. The key is used to retrieve value from a map.
When you put an entry of key/value pair into the map, the hash code of the key object is used to determine the bucket where the entry will be inserted. And then the key of the insert entry is used to compare with the existing entries to determine if it's an update or an insert.
When you get a value for given key from the map, the hash code of the key object is used to first determine the bucket. And then the search key object is used to compare with the key of the existing entries to further pinpoint the object to return if there. The equals() method is use for the comparison.
This is why hashCode() method and equals() method are very important when objects are used as keys in map/set.
If the hash algorithm is good, the buckets in the the map/set could be equally distributed and the map/set is fast and efficient to access.
If the hash algorithm is poor (e.g., always returning the same value), access is inefficient (e.g., one heavy bucket) or inconsistent performance (e.g., some buckets too heavier than the other).
Map and set are hash-based collections. So set works very similar to map as described above. Only difference is that values in set are also the keys.
#### Have you use ConcurrentHashMap? What's the difference between ConcurrentHashMap, HashMap and SynchronizedMap? What are the pros and cons among these data structures?
Yes. I used HashMay is not threadsafe. ConcurrentHashMap is threadsafe. SynchronizedMap is a quick way to turn any Map implementation into thread safe implementation by creating an adaptor with all synchronized methonds.
ConcurrentHashMap is the most efficient implementation because it is created with thread safty in mind.
Initially in Java, **Hashtable** is available as a map collection. It used a pessimistic locking strategy. All operations against this data structure are synchronized against the same global lock. Locks the whole map. This makes Hashtable thread-safe but not very efficient.
Then **HashMap** is available as an alternative. It has no locking. More efficient than Hashtable when locking is not required. But developers need to "wrap" it in **SynchronizedMap** when locking is necessary. The locking strategy in SynchronizedMap is also pessimistic. Locks the whole map. But SynchronizedMap is better than Hashtable in ensuring data consistency (Hashtable doesn't throw ConcurrentModificationException if the map is modified after the creation of the iterator. SynchronizedMap throw ConcurrentModificationException if the map is modified after the creation of iterator).
The **ConcurrentHashMap** is available as another alternative. Good for multi-thread use cases. The locking strategy is to divide the collection into segments/portions and to allow concurrent access to them according to that concurrency level. Locks some portions of the map instead of the whole map. Benefits: reduce the contention on the map, better performance than SynchronizedMap. Trade-off: each of the segments has own lock and some book-keeping variables (count, threshold etc), ConcurrentHashMap uses some minor extra memory for those overhead.
### What are volatile/transient in Java for?
**volatile** keyword is typically used on a variable used by different threads.
It tells java runtime not cache the changes in the CPU cache (i.e., flushes the changes directly to the main memory). And tells java runtime to always read the variable from main memory.
A machine could have multiple CPUs (each with their own local caches). Threads on different CPUs have their own copies of the variable in their local caches. When one thread change the variable, the value in local cache may not reflect the value in main memory. Other threads may not aware of the change. Thus data consistency issue.
volatile keyword tells java compiler not to optimize the access to use the CPU cache.
**transient** keyword is used to indicate that the member variable is not to be a part of serialization/deserialization process. When an object is persisted or transferred through the network, the object state is serialized into stream of bytes and then, on the other end, the stream of bytes is deserialized to recreate the object. The transient keyword indicates that the member variable is not to be a part of persistence and/or network transfer.
### Does volatile guarantee synchronization?
The volatile keyword is a "lightweight" synchronization mechanism.
So it does provide thread safety in some cases. When and why?
* When only one thread writes to the volatile variable and other threads read its value. Thus, the reading threads see the latest value of the variable.
* When multiple threads are writing to a shared variable such that **the operation is atomic**. This means that the new value written does not depend on the previous value.
But it does not provide thread safety in all cases. When and why?
* **when non-atomic operations or composite operations** are performed on shared variables. Reason: Unlike synchronized methods or blocks, volatile keyword does not make other threads wait while one thread is working on a critical section.
### What's the difference between heap and stack memory in Java? What types of objects are in them?
Heap - is used for the dynamic memory allocation of objects and the JRE classes at runtime. Objects we create are in heap.
Stack - is used for the static memory allocation and the execution of a particular thread. Primitives values that are specific to a method are in stack. The references to the objects in heap are also in stack.
When we create new objects, the objects are in heap space. And the references of these objects are in stack memory.
Features of heap space (copied from web search):
- It's accessed via complex memory management techniques that include the Young Generation, Old or Tenured Generation, and Permanent Generation.
- If heap space is full, Java throws **java.lang.OutOfMemoryError**.
- Access to this memory is comparatively slower than stack memory
- This memory, in contrast to stack, isn't automatically deallocated. It needs Garbage Collector to free up unused objects so as to keep the efficiency of the memory usage.
- Unlike stack, a heap isn't threadsafe as **all threads have access to the same heap**. So heap needs to be guarded by properly synchronizing the code.
Features of stack memory (copied from web search):
- It grows and shrinks as new methods are called and returned, respectively.
- Variables inside the stack exist only as long as the method that created them is running.
- It's automatically allocated and deallocated when the method finishes execution.
- If this memory is full, Java throws **java.lang.StackOverFlowError**.
- Access to this memory is fast when compared to heap memory.
- This memory is threadsafe, as **each thread operates in its own stack**.
### How does classloader works in Java?
Class loader is used by JVM to load java code and resources. There is a root class loader and each class has it's own classloader.
### How does garbage collector works in Java? What are GC roots and what are they for? Explain the different types of GC roots in Java.
GC is a foundation of JVM. It's responsible for release/recycle objects that is not used or is not reachable.
GC roots determine which objects are still in used. Objects that are directly or indirectly referenced from a GC roots are considered as live object thus not qualified to be garbage collected.
Types of GC Roots (copied from web search):
- Class: Classes loaded by a system class loader; contains references to static variables as well
- Stack Local: Local variables and parameters to methods stored on the local stack
- Active Java Threads: All active Java threads
- JNI References: Native code Java objects created for JNI calls; contains local variables, parameters to JNI methods, and global JNI references
### What is Closeable in Java? What interface to implement and method(s) to code to your class?
related to deep copy and shallow copy? That's Cloneable.
Closeable is to enable the class to be used in try-with-resources. The close() method you implement will be called automatically to release the resource you code (e.g., close db connection).
Similar to 'context manager' in Python.
### What is singleton and when would you want to use it? What are the different ways to implement a singleton in code?
(Jim)
### What is ThreadLocal and when would you want to use it? How to implement it in code?
ThreadLocal is used when we want a shared instance per thread. So we can acccess to the instances in a thread-safe manner without using the synchronized keyword. And not having to create one all the time.
Example: SimpleDateFormat is not thread-safe, having a singleton for the entire jvm would require synchronization. So, use multiple instances (one per thread) instead.
```java
// method to create the per-thread single instance
private static final ThreadLocal<SimpleDateFormat> perThreadSDF = new ThreadLocal<SimpleDateFormat>() {
@Override
protected SimpleDateFormat initialValue() {
return ( new SimpleDateFormat('yyyyMMdd') );
}
}
```
```java
// using it
SimpleDateFormat sdf = perThreadSDF.get();
// in thread1, first time when you call, the instance is created according to initialValue() method.
// in thread1, subsequent calls will use the same instance previously created. efficient.
Date date = sdf.parse(dateStr);
```
### If you need to synchronize access to a variable from multiple threads in a single writer and multiple readers use case scenarios, how would you implement it in your code to control access/locking of that variable? How about in a scenarios of multiple writers and multiple readers? How about in a scenarios of multiple writers and single reader?
(Jim)
Application Architecture
---
### Give me a high-level overview of the architecture of the applications you worked on at ABN AMRO.
Suggestion: 3 or 4 sentences on the technical components in the architecture (web front-end, app server, db, vendors integration, etc). 1 sentence on primary business purpose of the system.
(Jim)
### How does the architecture of the applications you worked on at Bank of America look like?
(Jim)
### Give me a high-level overview of the architecture of the applications you worked on at JP Morgan.
(Jim)
Cloud Technologies
---
### Explain Quartz as a private cloud.
Quarts has building CI/CD pipeline and tools that support collaberations and manage the artifacts (approval email).
serverless - in cloud - lambda is a piece of funciton that
Quartz is a private cloud enviroment within Bank of America.
It is an on-premise internal cloud with datacenters own and manage by the bank, not a private cloud dedicately renting from external third-party datacenters.
Quartz's service delivery model is PaaS. It provides all the **infratructure** capability (virtual machines, storage, networking) as well as all the **runtime** capability (runtime platform, middleware, host OS) within the bank. More than that, it also provides tools and support for entire SDLC. From software development (IDE) to build and deployement (CI/CD pipeline) to production DevOps. Additionally, it also has real-time messenger tool for team members across teams and roles to collaborate and support each other.
Quartz also supports "serverless" deployment model. To supports the many of apps and functionalities that are event/message driven or are of reactive nature.
### Explain grid computing in Quartz
grid computing - map reduce
describe map recuce - example - risk mesaure interest sensitivity.
a grid note is computation unit. it doesn't have data, data stored in a database is nearby to the node.
### What is Docker and Kubernete? Explain how you use them in your projects?
Docker story - containization
bare metal - physical machine
virtual of machine, network, storage
storage is hadoop
Docker runs on virtual or host os.
Docker runs on top host os (linux, windows, mac), it boundle the dipendent libraries.
Python
---
### How long have you been using Python? What did you used it for? Which apps or projects?
5+ years. I coded in Python exclusively for BOA and Crypto Caverns. It used it for creating apps and servers including API servers uisng Flask. I also used pandas in my crypto mining reports and calculator app.
### How does your application development looks like in Python? IDE, build tool, etc?
Have used Visual Studio Code, Quartz IDE and Jupyter notbook. Also tried IntelliJ IDE.
PyScaffold - to generate initial project. It setup the project with the standard directory structure and artifacts to support development and deployment. The **setup.cfg** file is used to support development (similar to the pom.xml file in Maven world for Java). The **requirements.txt** is to support deployment (similar to the install target in pom.xml).
Two ways to build the project:
- either the source distribution (sdist) which produces the project.tar.gz file as deliverable artifact.
- or the binary distribution (bdist) which produces the project.whl as deliverable artifact. Wheel distribution is the most popular format for binary deliverable, there are other binary format but we haven't used.
To deploy the build into the runtime machine, the artifact (tar or whl) can be installed using pip. Command:
pip install filename
In Quartz, we used the set of tools under the environment. The tools there are propriety but the capabilities are similar.
### How does list comprehension works in Python? What's the benefits of using it?
Python allows creating a new list based on an existing sequence using a very compact syntax.
benefits are: a. increased code readability b. no need to loop, reduced complexity and chances for bugs assocaited with looping c. more efficient.
### What's the difference between list and tuple?
list is mutable. tuple is immutable.
### How to perform union and intersection operations for two sets in Python?
x.union(y)
x.intersetion(y)
### What is context manager in Python? What methods do you need to implement in a class to qualify it to be a context manager?
Hint: to be able to use the class in a 'with' statement. Similar to closeable in Java, to be able to use with try with.
Context manager allows for implicitly releasing a resource when it done using it. It defineds an interface with an \_\_enter\_\_() and \_\_exit\_\_() method. When the executing with block, enter is called, when exsiting with block, exit is call. It provides hooks for developers to implement logic to prepare resources and to release resourses.
### Explain how Python threading works?
CPython interpreter only allows one OS thread running at a time. Logically, you can implement multiple threads in python code.
### What's coroutine?
CI/CD Questions
---
### Explain your CI/CD pipeline?
Our team is responsile for over 100 java projects and a big J2EE project. We need to build multiple jars and wars and release them to production environment.
In ABN, we use Jenkins to manage our CI/CD pipeline. It pulls source code from SVN and build and copy the binaries to DEV. It then kicks off JUnit test to run all unit tests. If tests failed, we'll receive an email with error messages and we need to manually fix the issue and submit a fix. If all tests passed, the jars/wars will be copied to Dev and QA environments. We would run a manual regression tests and also test the new features if any. When QA tests passed, we would approve the build and send instructions to Ops team to get the binaries/configurations released. We then will test on production or ask use to test on production. All passed, the release is completed.
At ABN AMRO, most of our projects are in **SVN** and some recent ones are in **Git**. And our projects are Java applications so we are using **Maven and Gradle** for build/packaging and **JUnit** for Unit Testing. And we use **Jenkins** in our CI/CD pipeline and Jenkins pulls source code from SVN/Git. For libraries projects, the buils for them in Jenkins are **triggered as soon as we submit any change** to SVN/Git. For applications (GC, Subway, Batch Executables) projects, the builds for them in Jenkins are **scheduled on an hourly basis as well as daily basis**. The build happens according to how we setup Maven pom.xml and unit test cases are automatically executed as part of the builds.
Jenkins does two things when triggering the build:
* `svn update / git update` (to update the workspace with the latest source code from SVN/Git)
* `mvn clean install` (to cleanup previous build, and then compile->package->install). install for libraries works differently for web apps.
* Locally on developers machines:
* we call `mvn clean install` only for library projects. So that library jar is installed into our local maven cache (~/.m2 location).
* we call `mvn clean package` in application projects
* if we call `mvn clean install` in application projects, the build install the artifacts to DEV machine.
Once the build in Jenkins is successfully completed, for a library project Jenkins installs the build artifact (jar) the into ABN's maven repository location making it available for apps to use. And for application project Jenkins saves the build artifact (jars, wars, runtime configurations) in a location that are available to be deployed into runtime environments (UAT, PROD, etc). Deployment to UAT happens immediately at that time. PROD deployment happens on Friday night when we have a release.
For libraries,
* when `mvn clean install` on developer desktop, jar gets installed into local maven cache (~/.m2 location).
* when `mvn clean install` on Jenkins machine, jar gets installed into ABN's maven repository.
For applications,
* maven looks for the dependent jars in local cache first. if not there, looks for them in ABN's maven repository. And, if not there, looks for them in Maven Central out there.
* For internal jars, only in local cache for ABN's maven repository. For external jars, could be one of those 3 locations.
* For all compile dependencies,
* for web-applications, dependent jars are bundled into the package as part of deliveriable artifact (war).
* for batch console apps, we use thin packaging, dependent jars are not bundled into the package as part of deliverable artifact (jar).
* dependent jars are common among our batch console apps and rarely change, so we install them separately.
**Local Developer's desktop:**
libraries -> developer do mvn clean install (clean -> compile -> package -> install). installed to local maven cache.
apps -> developer do mvn clean package (clean -> compile -> package). Then use tomcat server in eclipse.
**UAT/DEV:**
libraries -> Jenkins calls mvn clean install. installed to ABN's maven repo.
apps -> Jenkins calls mvn clean install --target DEV. result: app war installed to DEV server.
apps -> Jenkins calls mvn clean install --target UAT. result: app war installed to UAT server.
**PROD:**
apps -> manual procedure. special instruction to IT Support to release the war into Production.
(mvn clean install --target PROD won't work).
### How do you set up Jenkins?
We use the Jenkins' admin tool to add the SVN repository path and added scripts to copy the binaries to shared folders from build machine to DEV and QA machines.
When we installed Jenkins onto our build server at ABN, the Jenkins server is a Windows service on our Windows Server machine. We configured Jenkins on a designate port. And that port is how we access Jenkins admin console. In there, that where we setup for build projects. For each of projects, we specified the URL to its source code in SVN/Git. How the build should be triggered (e.g., upon code submission, on a particular schedule time, etc). And command to run for the build (e.g., mvn clean install).
Jenkins itself has a weekly release schedule. So, as part of Jenkins admin/maintenance, we review Jenkins upgrades and plugins once a week to ensure we are up-to-date with Jenkins as well as its plugins. So we don't have vulnerabilities in our Jenkins server.
### Explain how Maven works.
(don't think we need a seperate section for Maven. will delet it.)
### SVN vs Git
SVN is a centralized version control system. The SVN server needs to be available for developers to work with.
checkout, branching, checkin, etc directly against SVN server. Live connection required.
commands: ....
Git is a version control system that support distributed development. Git main repo is out there. But, most of the time, developers work with a local repo (that has been clone).
clone - copies the entire repo from central repo to your desktop.
add, commit, ... - concept as SVN. But only against your local repo.
push - propagate the changes you committed to your local repo to the central repo.
When main repo not available, you can still add, commit, and etc so you can still do your work. Except push or pull or clone.
And then when main repo is available again, you can push the changes to main repo.
When you do a git push (as an individual contributor), the changes you push don't immediately go into main repo. The owner of the main repo will perform a review to allow your changes to get there.
### Git branch
- concept is similar to SVN.
- but Git branch in Git is more lightweight than SVN. So use a lot more often. As an independent line of development, usually created for working on a feature. Branches let developers code without affecting the work of other team members.
Typical git workflow using branch and merge:
``` bash
# Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Merge in the new-feature branch
git checkout main
git merge new-feature
git branch -d new-feature
```
### What is CI/CD?
**Continuous integration (CI)** executes the sequence of steps required to build and test the project. CI runs automatically on every change committed to a shared repository, offering developers quick feedback about the project’s state.
**Continuous delivery (CD)** is an extension of CI. Its goal is to automate every step required to package and release a piece of software. The output of a continuous delivery pipeline takes the form of a deployable binary, package, or container.
Git, Maven/Gradle, JUnit, Jenkins, etc - tools we used to do CI/CD at ABN.
### Some benefits of CI/CD?
improve quality
early detection of problems from code changes - via unit tests
Ensures early detection of conflicted code or imcompatible code by submitted by different developers.
Small incrementle changes can be easily tested and rolled back if not working.
Interview Preparations
---
### Questions to employers
Good general ideas to drive questions to ask. But ask in some ways to avoid sounding cursory or by-the-book. Show that you are engaged in current conversation. And that you are very interested in finding out what they are looking for and what you are walking into when joining the team.
1. How long have you been looking for a candidate?
(e.g., how long has this position been open? if long, any reason why it has been open for so long?
*Poke on their recruiting process/issue: on-and-off in hiring freezes, expectations reasonable or unreasonable, which of particular expectations previous candidates were not able to meet, what's are the key main real needs/requirements for the role, etc.*)
3. What are the resposibiliteis for this role in the first 90 or 180 days?
(e.g., my understanding is that I will be working on ... in the initial 3 months. Like to confirm how accurate this is, etc.
*Sum up what you picked up from the interview. To get better feel for how well-defined is the role and responsibilities? they may not have the clear solid answer. also, if their environment is agile, things evolves.*)
5. Would I be working on a project solely or collaberately with other members?
(e.g., % of time team members work independently vs together? tools for collaboration? etc
*Sum up what you picked up from the interview. To poke further on their corporate culture and potential issues there, how well team members collaborate, what works and what not for them, etc.*)
4. What type of skill sets are you looking for?
(e.g., my understanding is that you need an engineer with ... skill sets. Like to confirm if anything missing, which skills are more immediately important than the other, which skills are for longer-term, etc.
*Sum up what you picked up from the interview. To get better feel for how the environment is evolving, how to succeed in immediate-term and in longer-term, how the environment enable or support team members learning/upskills, etc.*)
5. Any additional questions you have for me at this point? Any concern I should address from our conversations?
6. What is the next step in the interview process? When can I expect to hear from you? If I have additional questions for you later, could I check with you directly?
7. What are you shortcomings?
Overengineering. Perfect.
### How to be indispensible at work?
Understanding how everyone else works
Effort you are going to put it
Skills you are going to build
Collecting what you have acomplished.
The context of what you are doing, the players
The value added to the company
How long does it take to complete the project.
Projects to improve skills
---
### Project: Move my trading alert application to AWS cloud.
souce code: https://github.com/jwangus/insider-trading
https://github.com/jwangus/creports
1. The architecutre
2. The CI/CD pipeline
3. Set up AWS
1. Create an account
2. Provision
3. Deployment
4. ...
DRW interview
---
Filename: tetris.py
```python
import sys
import collections
Block = collections.namedtuple('Block','nodes width height'.split(' '))
BLOCKS = {
'Q': Block(((0,0),(1,0),(0,1),(1,1)), 2, 2),
'Z': Block(((1,0),(2,0),(0,1),(1,1)), 3, 2),
'S': Block(((0,0),(1,0),(1,1),(2,1)), 3, 2),
'T': Block(((1,0),(0,1),(1,1),(2,1)), 3, 2),
'I': Block(((0,0),(1,0),(2,0),(3,0)), 4, 1),
'L': Block(((0,0),(1,0),(1,0),(2,0)), 2, 3),
'J': Block(((0,0),(1,0),(1,1),(1,2)), 2, 3),
}
class Grid:
MAX_HEIGHT = 100
MAX_WIDTH = 10
def __init__(self) -> None:
self._g = [[0] * self.MAX_HEIGHT for i in range(self.MAX_WIDTH)]
def max_height(self, start=0, end=MAX_WIDTH):
return max([self.height(col) for col in range(start, end)])
def height(self, col):
for i in range(self.MAX_HEIGHT, 0, -1):
if self._g[col][i-1] == 1:
return i
return 0
def drop(self, block, col_num):
# try from the max height under the block
max_height = self.max_height(col_num, col_num+block.width)
finanl_pos = max_height
stop_try = False
for y in range(max_height-1,-1,-1):
for nx, ny in block.nodes:
if self._g[col_num + nx][y + ny] == 1:
# the node is taken. cannot put the block here
stop_try = True
break
else:
# this is a good positon for the block
finanl_pos = y
if stop_try:
break
# we found a palce, mark the nodes in the grid
for nx, ny in block.nodes:
self._g[col_num + nx][finanl_pos + ny] = 1
while (self.remove_a_fill()):
pass
return
def remove_a_fill(self):
for y in range(self.MAX_HEIGHT):
row = [self._g[x][y] for x in range(self.MAX_WIDTH)]
if sum(row) == self.MAX_WIDTH:
for col in self._g:
del col[y]
col.append(0)
return True
return False
def main():
grid = Grid()
for l in sys.stdin.readlines():
for command in l.split(','):
c = command.strip()
if not c:
continue
grid.drop(BLOCKS[c[0]], int(c[1:]))
print(grid.max_height())
if __name__=='__main__':
main()
```
Command to run:
`python tetris.py < input.txt > output.txt`
Input vs Expected Output:
*Trying to understand if each of input line can be treated as independent case or if they should be accumulated on top of previous input lines)*
```
Q0 # 2
Q0,Q1 # 4 (or 4 + 2 = 6)
Q0,Q2,Q4,Q6,Q8 # 0 (or 0 + 6 = 6)
Q0,Q2,Q4,Q6,Q8,Q1 # 2 (or 2 + 6 = 8)
Q0,Q2,Q4,Q6,Q8,Q1,Q1 # 4 (or 4 + 8 = 12)
I0,I4,Q8 # 0 (or 0 + 12 = 12)
I0,I4,Q8,I0,I4 #
L0,J2,L4,J6,Q8
L0,Z1,Z3,Z5,Z7
T0,T3
T0,T3,I6,I6
I0,I6,S4
T1,Z3,I4
L0,J3,L5,J8,T1
L0,J3,L5,J8,T1,T6
L0,J3,L5,J8,T1,T6,J2,L6,T0,T7
L0,J3,L5,J8,T1,T6,J2,L6,T0,T7,Q4
S0,S2,S4,S6
S0,S2,S4,S5,Q8,Q8,Q8,Q8,T1,Q1,I0,Q4
L0,J3,L5,J8,T1,T6,S2,Z5,T0,T7
Q0,I2,I6,I0,I6,I6,Q2,Q4
```
Job requirements
---
As a Full Stack Developer with a passion for innovation, you’ll join our high-performance development team, revolutionizing work for HR managers and practioners. You will design, develop, and deploy enterprise solutions, including angular components and innovative AI features. This includes features across the AI spectrum such as Chatbot, Knowledge Management & Congnitive Services to support 3.5+ billion end user logins.
To thrive in this role, you’ll need to be an expert in JavaScript fundaments, have current hands-on experience with the Angular framework & experience with Typescript in a strongly typed ecosystem. You’ll also need hands-on experience working with & developing APIs, CSS, Lambda, current use of or interest in learning GraphQL, and strong knowledge in ESCMA script standards, unit test and end to end test frameworks with experience in writing good tests.
**Some general high-level questions:**
### How long have you been developing applications uing JavaScript, Angular and Typescript?
(Jim)
### What are some of the tools have you been using in developing your applications? How do they fit together in you projects and development process?
*(IDE, buid tool, unit testing tool, package management tool, CI/CD tool, etc - in your Angular/Typescript development process)*
(Jim)
### How does apps development with Angular looks like?
*(i.e., how did you use Angular and how does it fit into your app developement process? anything you benefited from using it? any difficulty you encountered from using it? how steep was the learning curve and how long to become competent?)*
(Jim)
### What are some key components of Angular? How do they work together in your apps?
(Jim)
### What test framework(s) have you used for various testing stages of your apps in Angular/Typescript projects? for unit testing, for higher-level testing, ...? Some details on how you used them?
(Jim)
### How does Typescript relates to Javascript? How are these relate to ECMA scripts ecosystem and standards?
(Jim)
### How does your program in Typescript compile or transpile into Javascript? Where does this compilation/transpilation happens? in the browser? or before that?
(Jim)
### How does CSS fit into your apps? What did you used it for, etc?
(Jim)
### How does Lambda fit into your apps? What did you used it for, etc?
(Jim)
### What can you tell me about GraphQL? What is it for, etc? If you are not experienced with it, how long do you think it takes for you to get up to speed with it?
(Jim)
### What was your past experience in developing large scale apps that support large volume and/or large number of users? What was some of the technical challenged you encountered in such apps? And how did your team handled them?
*(usually a very interesting situation. tell us the story from that experience. we may encounter something similar that we can relate to that experience here).*
(Jim)
https://www.interviewbit.com/spring-security-interview-questions/
TD Tech Challenge
---
**Requirements**
- It is necessary to implement a component for solving quadratic equations.
- In addition to a standard API the solution should provide an "integration" text-based interface, e.g. used in a HTTP-based service or by a component implementing file-based exchange.
- That interface should accept a string as input and produce a string. The format of the input and output is defined by the component's developer. The input and output format should be machine-parsable.
- The solution should come with corresponding test coverage.
- Please submit the solution via a github repo
- The solution should be built in Java 8+ using Spring Boot. The reviewers will look for:
- Best coding practices (unit tests…)
- Exception handling / input validation / choice of data types
- Patterns, optimal use of Spring Boot construct and use of relevant third party libraries (i.e. use of Jackson for JSON output)
**Analysis:**
Implement a solution for solving quadratic equations.
**Summary of Conditions for Quadratic equations (code to check for):**
1. Quadratic Equation in Standard Form:
$$ ax^2 + bx + c = 0
$$
2. Quadratic Formula:
$$
x = {-b \pm \sqrt{b^2-4ac} \over 2a}
$$
3. When the Discriminant $$(b^2 − 4ac)$$ is:
- positive, there are 2 real solutions
- zero, there is one real solution
- negative, there are 2 complex solutions. **Assumption: we are not going to support this condition.**
**Input:**
Please enter the quadratic equation in Standard Form:
* We'll use regex to parse input string:
ax^2 + bx + c = 0
```java
// in a java package under src/main/java directory.
public final class QuadraticEq {
// not working too well.
// private static final Pattern EQN = Pattern.compile("([+-]?\\d+)[Xx]2\\s*([+-]?\\d+)[Xx]\\s*([+-]?
// this works!
private static final Pattern EQN = Pattern.compile("([+-]?\\d*)x\\^2\\s*(([+-]?\\d*)x(?!\\^))?\\s*([+-]?\\d*)(?!x)\\s*=\\s*0");
private final int a;
private final int b;
private final int c;
private QuadraticEq(int a, int b, int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static QuadraticEq parseString(final String eq) {
String eqx = eq.replaceAll("\\s", "");
final Matcher matcher = EQN.matcher(eqx);
if (!matcher.matches()) {
throw new IllegalArgumentException("Not a valid pattern " + eq);
}
//final int a = Integer.parseInt(matcher.group(1));
//final int b = Integer.parseInt(matcher.group(2));
//final int c = Integer.parseInt(matcher.group(3));
// Our regex above has 4 groups instead of 3 groups.
// group 3 now is a subgroup of group 2.
// group 4 now is same as group 3 before.
// group1 could be empty or a number.
final int a = Integer.parseInt( evalA(matcher.group(1)) );
// group3 could be null, empty or a number.
final int b = Integer.parseInt( evalBC(matcher.group(3)) );
// group4 could be null, empty or a number.
final int c = Integer.parseInt( evalBC(matcher.group(4)) );
return new QuadraticEq(a, b, c);
}
private static String evalA(String str) {
/* if (str == null) { // 1st group never get this.
return "0";
} else */
if (str.equals("")) {
return "1"; // 1st group always exist, empty is implicitly 1.
} else if (str.equals("+")) {
return "+1";
} else if (str.equals("-")) {
return "-1";
} else {
return str;
}
}
private static String evalBC(String str) {
if (str == null) {
return "0"; // missing 2nd or 3rd group.
} else if (str.equals("")) {
return "0"; // missing 2nd or 3rd group.
} else if (str.equals("+")) {
return "+1";
} else if (str.equals("-")) {
return "-1";
} else {
return str;
}
}
public int getA() {
return a;
}
public int getB() {
return b;
}
public int getC() {
return c;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("QuadraticEq {");
sb.append("a=").append(a);
sb.append(", b=").append(b);
sb.append(", c=").append(c);
sb.append('}');
return sb.toString();
}
public static void main(String[] args) {
String testStr[][] = {
{"5x^2+3x+1=0", "5", "3", "1"},
{"5x^2 + 3x + 1 = 0", "5", "3", "1"},
{"-5x^2 - 3x - 1 = 0", "-5", "-3", "-1"},
{"1x^2 - 4 = 0", "1", "0", "-4"},
{"x^2 - 4 = 0", "1", "0", "-4"},
{"2x^2 - 4x = 0", "2", "-4", "0"},
{"x^2 + x + 1 = 0", "1", "1", "1"},
{"x^2 - x - 1 = 0", "1", "-1", "-1"},
{"+x^2 + x + 1 = 0", "1", "1", "1"},
{"-x^2 - x - 1 = 0", "-1", "-1", "-1"},
{"x^2 + x = 0", "1", "1", "0"},
{"x^2 - x = 0", "1", "-1", "0"}
};
for (String test[] : testStr) {
// equation to test parsing.
String eqStr = test[0];
// expected coefficients.
String a = test[1];
String b = test[2];
String c = test[3];
System.out.println();
// parse the equation.
QuadraticEq eq = parseString(eqStr);
System.out.println(eq);
System.out.println("Expecting {a="+a+", b="+b+", c="+c+"}");
}
}
}
```
```java
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.Test;
// in a java package under src/test/java directory.
class QuadraticEqTests {
@Test
void test() {
String testCases[][] = {
{"5x^2+3x+1=0", "5", "3", "1"},
{"5x^2 + 3x + 1 = 0", "5", "3", "1"},
{"-5x^2 - 3x - 1 = 0", "-5", "-3", "-1"},
{"1x^2 - 4 = 0", "1", "0", "-4"},
{"x^2 - 4 = 0", "1", "0", "-4"},
{"2x^2 - 4x = 0", "2", "-4", "0"},
{"x^2 + x + 1 = 0", "1", "1", "1"},
{"x^2 - x - 1 = 0", "1", "-1", "-1"},
{"+x^2 + x + 1 = 0", "1", "1", "1"},
{"-x^2 - x - 1 = 0", "-1", "-1", "-1"},
{"x^2 + x = 0", "1", "1", "0"},
{"x^2 - x = 0", "1", "-1", "0"}
};
for (String test[] : testCases) {
// equation to test parsing.
String eqStr = test[0];
// expected coefficients.
String a = test[1];
String b = test[2];
String c = test[3];
System.out.println();
// parse the equation.
QuadraticEq eq = QuadraticEq.parseString(eqStr);
System.out.println(eq);
System.out.println("Expecting {a="+a+", b="+b+", c="+c+"}");
assertTrue ( a.equals(eq.getA()+"") ) ;
assertTrue ( b.equals(eq.getB()+"") ) ;
assertTrue ( c.equals(eq.getC()+"") ) ;
}
}
}
```
* Supporting other forms could be an enhancement later if time allows.
Input is the equation in various formats. Examples:
$$ 5x^2 + 3x + 1 = 0
$$
$$ x^2 = 3x - 1
$$
$$ 2(w^2 - 2w) = 5
$$
$$ z(z - 1) = 3
$$
$$ x^2 -4 = 0
$$
$$ 2x -4 = 0
$$
**Output:**
- given input string is a valid or an invalid quadratic equation.
- if valid, expected type of solution (determine by the Discriminant above).
- The solution(s).
- if real value(s), fine.
- if complex values, how to represent them? e.g.,
$$ x = {{4 ± 3i} \over 2}
$$
*(We are not going to support this case per assumption above)*
**Testing:**
a file like csv or a map with following:
- 1st column: a string as a given input equation
- 2nd column: output (valid or invalid equation)
- 3nd column: result(s)
x^2 - 4 = 0, valid, x = -2, x = 2
....
Standard API
HTTP GET
http://localhost/api/v1/quadratic-equation-solver/x^2-4=0
HTTP Response
200 ok
Body
{}
RestController
map to a service call
// CalcService can be injected into other components to solve equation,
// e.g. used in a HTTP-based service or by a component implementing file-based exchange.
CalcService
public String solve (String equation) throws ... {
}
**More brainstorming:**
After parsing (including unfactoring x^2 - 3x + 1 = 0 for second example, 2w^2 - 4w - 5 = 0 for third equation, z^2 - z - 3 = 0 for 4th example):
- we should be able to determine if the input equation is a valid quadration equation or not.
- we should be able to determine the constants for a, b, c
If not valid equation, error out.
If valid, compute the two values for the variable in the equation. x, w, z
**References:**
[quadratic-equation](https://www.mathsisfun.com/algebra/quadratic-equation.html)
[how to parse equation in Java](https://stackoverflow.com/questions/4681959/algebra-equation-parser-for-java)
[Extract coefficients from quadratic equation](https://stackoverflow.com/questions/29720136/java-program-to-extract-coefficents-from-quadratic-equation)
[Spring Expression Language](https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions)
**Some potential questions:**
1. What's the point of solving a quadratic equation? What does the solution(s) tell us?
- So we know the two points in the equation on the x-axis. For example, with the solutions of x=1 and x=3, the two points on the graph we can plot are (1,0) and (3,0).
- if the solution(s) are real number(s), the graph crosses the x-axis.
- if the solution(s) are complex number(s), the graph does not cross the x-axis.
- remember that $$ax^2 + bx + c = 0$$ is a special case of $$ax^2 + bx + c = y$$. Where y is f(x), a function of x.
2. So, we know where the graph crosses the x-axis, how do we determine the point where it crosses the y-axis?
- set x to 0 in the equation to find y. Then y = c so the point is (0, c). Example: for $$2x^2 - 3x + 1 = y$$, y = 1, the graph crosses y-axis at (0,1).
3. So, we have the x-intercepts and the y-intercept, what else do we need to determine how the shape of the graph looks like?
- we need (a) the vertex & we need (b) to determine if the graph is upward opening or downward opening.
4. How to calculate the vertex?
Formula: $$h = {-b \over 2a}$$ and the plug-in h into the quation to find k. Vertex is the point (h, k).
Example: $$y = x^2 − 4x + 3$$.
Then a=1, b=-4, c=3.
$$h = {4 \over 2*1} = {4 \over 2} = 2$$
$$k = 2^2 - 4(2) +3 = 4 - 8 + 3 = -1$$
Vertex is (2, -1)
5. How to determine if upward opening or downward opening?
If a is greater than 0, it's upward opening. If a is less than 0, it's downward opening.
Example: $$y = x^2 − 4x + 3$$.
Then, with a=1, we know its graph is upward opening.
5. Would it makes sense to return all these calculations as part of the result?
{
x-intercepts:
y-intercept:
vertex:
opening:
...
}
**Code review comments:**
1. eqPattern = Pattern.compile("([+-]?\\d*|\\d+)x2([+-]?\\d*)x([+-]?\\d+)?=0\\s*"); -- should be a static line for performance reason. expensive, reusable.
2. the second term in the equation is optional, forcing users to enter 0x is quite unpolished and could be improved. Suggested change:
```java
static final var EQ_PATTERN = Pattern.compile("([+-]?\\d*)x2(([+-]?\\d*)x)?([+-]?\\d+)?=0\\s*");
public List<Integer> extractCoefficients(String equation) throws SolverException {
// var eqPattern = Pattern.compile("([+-]?\\d*|\\d+)x2([+-]?\\d*)x([+-]?\\d+)?=0\\s*");
var eqPattern = Pattern.compile("([+-]?\\d*)x2(([+-]?\\d*)x)?([+-]?\\d+)?=0\\s*");
<!-- var eqPattern = Pattern.compile("([+-]?\\d*)x2\\s* (([+-]?\\d*)x)?\\s* ([+-]?\\d+)?\\s* = 0\\s*"); -->
// 1st term (required): ([+-]?\\d*)x2 is the same as ([+-]?\\d*|\\d+)x2
// 2nd term (optional): (([+-]?\\d*)x)? and the inner subgroup ([+-]?\\d*) is for coefficient b
// 3rd term (optional): ([+-]?\\d+)?
// * is for 0 or multiple (i.e., option)
// + is for 1 or multiple (i.e., required)
// ? means optional. no ? means required.
Matcher matcher = eqPattern.matcher(equation.replaceAll("\\s", ""));
if (matcher.matches()) {
List<Integer> r = new ArrayList<>();
// we don't normally blindly process all groups in regex.
/*
for (int i=1; i<=3; i++) {
try {
r.add(Integer.parseInt(translate(matcher.group(i))));
} catch (Exception e) {
throw new SolverException("Not a quadratic equation.");
}
}
*/
// typically cherry-pick groups with intended semantic.
r.add(Integer.parseInt(translate(matcher.group(1))));
r.add(Integer.parseInt(translate(matcher.group(3))));
r.add(Integer.parseInt(translate(matcher.group(4))));
return r;
} else {
throw new SolverException("Not a quadratic equation.");
}
}
```
```java
@Test
public void extractCoefficientsTest() throws SolverException {
var result = service.extractCoefficients("10x2+x+1=0");
assertEquals(result, Arrays.asList(10, 1, 1));
result = service.extractCoefficients("x2+x+1=0");
assertEquals(result, Arrays.asList(1, 1, 1));
result = service.extractCoefficients("5x2-5x+10=0");
assertEquals(result, Arrays.asList(5, -5, 10));
result = service.extractCoefficients("500x2-1999x+299=0");
assertEquals(result, Arrays.asList(500, -1999, 299));
result = service.extractCoefficients("-5x2 - 3x - 1 = 0");
assertEquals(result, Arrays.asList(-5, -3, -1));
result = service.extractCoefficients("1x2 + 0x - 4 = 0");
assertEquals(result, Arrays.asList(1, 0, -4));
result = service.extractCoefficients("1x2 + 0x = 0");
assertEquals(result, Arrays.asList(1, 0, 0));
// these cases should pass unit testing.
result = service.extractCoefficients("x2 - 4 = 0");
assertEquals(result, Arrays.asList(1, 0, -4));
result = service.extractCoefficients("2x2 - 4x = 0");
assertEquals(result, Arrays.asList(2, -4, 0));
result = service.extractCoefficients("x2 + x + 1 = 0");
assertEquals(result, Arrays.asList(1, 1, 1));
result = service.extractCoefficients("x2 - x - 1 = 0");
assertEquals(result, Arrays.asList(1, -1, -1));
result = service.extractCoefficients("+x2 + x + 1 = 0");
assertEquals(result, Arrays.asList(1, 1, 1));
result = service.extractCoefficients("-x2 - x - 1 = 0");
assertEquals(result, Arrays.asList(-1, -1, -1));
result = service.extractCoefficients("x2 + x = 0");
assertEquals(result, Arrays.asList(1, 1, 0));
result = service.extractCoefficients("x2 - x = 0");
assertEquals(result, Arrays.asList(1, -1, 0));
}
```
json: {"answers":[-1.0,-0.2],"equation":"5x2+6x+1=0","description":"Solved."}
answers of [-1.0, -0.2] means x-intercepts: (-1.0, 0) and (-0.2, 0) points.
y = ax2 + bx + c is general function
ax2 + bx + c = 0 is to get the x-intercepts (we plugged in 0 for y)
how do you get the y-intercepts? answer: plug in 0 for x in the general function.
x2 - 4 = y
y = -4 the point (0, -4) is the y-intercept
**Note for Eclipse users (to get eclipse recognize Lombok annotations):**
1. download the Lombok jar:

2. run the jar to add to eclipse:

3. restart eclipse. errors related to Lombok annotations should go away.
**Additional question?**
1. How would you change the regex to support ax^2 + bx + c = 0 ?
change this:
```java
static Pattern EQ_PATTERN = Pattern.compile("([+-]?\\d*)x2(([+-]?\\d*)x)?([+-]?\\d+)?=0");
```
to this:
```java
static Pattern EQ_PATTERN = Pattern.compile("([+-]?\\d*)x\\^2(([+-]?\\d*)x)?([+-]?\\d+)?=0");
```
2. How would you change the regex to support ax**2 + bx + c = 0 ?
change this:
```java
static Pattern EQ_PATTERN = Pattern.compile("([+-]?\\d*)x2(([+-]?\\d*)x)?([+-]?\\d+)?=0");
```
to this:
```java
static Pattern EQ_PATTERN = Pattern.compile("([+-]?\\d*)x\\*\\*2(([+-]?\\d*)x)?([+-]?\\d+)?=0");
3. How would you change the regex to accept all 3 possible different formats users may enter?
ax2 + bx + c = 0
ax^2 + bx + c = 0
ax**2 + bx + c = 0
```java
static Pattern EQ_PATTERN = Pattern.compile("([+-]?\\d*)x[\\^|\\*\\*]?2(([+-]?\\d*)x)?([+-]?\\d+)?=0");
```
java package name: com.<company>.<team>.math.quadratic
group name in: com.<company>.<team>
artifact name: math-quadratic
Microservice: put everything (model, repo, service, controller) for the feature under the same java package
Group code by **layers** (all models into model package, all services into service package, all controllers into controller package, etc) -vs- group code by **features**.
**Exceptions:**
```java
public class SolverException extends Exception {
public SolverException(String msg) {
super(msg);
}
// Custom exception usually has this. To extend/wrap the original exception instead of eating it away.
public SolverException(String msg, Throwable causedBy) {
super(msg, causedBy);
}
}
```
May also want to have exceptions such as InvalidEquationException, UnsupportedException (e.g., complex solution), and so on instead of a catch-all and relying on the message in there.
**Some Coding Style/Design:**
*(Brainstorming ... In case similar questions come up during code review ...)*
- does SolverService.extractCoefficients() needs to return a full-blow List when we know that it will always return 3 values?
- does SolverService.solve() needs to return a full-blown List when we know that it will always return 2 values?
- SolverService maybe doing more than it supposed to. May want to refactor most of those logic into a business-object class like QuadraticEquation. Then SolverService would have only two methods as interface points. With few lines of code to delegate the work to QuaraticEquation.
- When knowing the expected size, may want to use an array instead of list. For efficiency reasons. Better to avoid passing them around when not necessary.
- if agree and refactor, replace all calls to service.extractCoefficients() to service.solve() in SolverServiceTests.java
```java
@AllArgsConstructor @Getter @ToString
public class Answer {
final double x1;
final double x2;
}
@AllArgsConstructor
@Setter @Getter @ToString
public class SolverResponse {
private /* List<Double> */ Answer answer;
private String equation;
private String description;
}
```
```java
@Service
public class SolverService {
public SolverResponse solve(String equation) throws SolverException {
try {
QuadraticEquation quad = new QuadraticEquation(equation);
Answer results = quad.solve();
return new SolverResponse(results, equation, "Solved.");
} catch (InvalidEquationException | UnsupportedComplexNumber e) {
throw new SolverException(e.getMessage(), e);
}
}
public /* List<Double> */ Answer solve(int a, int b, int c) throws SolverException {
try {
QuadraticEquation quad = new QuadraticEquation(a, b, c);
Answer results = quad.solve();
return results;
} catch (InvalidEquationException | UnsupportedComplexNumber e) {
throw new SolverException(e.getMessage(), e);
}
}
}
```
```java
@Setter @Getter @ToString
public class QuadraticEquation {
private static Pattern EQ_PATTERN = Pattern.compile("([+-]?\\d*)x2(([+-]?\\d*)x)?([+-]?\\d+)?=0");
// 1st term (required): group 1 - ([+-]?\\d*)x2
// 2nd term (optional): group 2 - (([+-]?\\d*)x)? and group 3 - the inner subgroup ([+-]?\\d*) is for coefficient b
// 3rd term (optional): group 4 - ([+-]?\\d+)?
@AllArgsConstructor @Getter @ToString
public static class Coefficient { // meaning only within the context of QuadraticEquation.
private final int a;
private final int b;
private final int c;
}
// input
private final Coefficient coefficient;
/**
* Builds an equation from given string. May throw InvalidEquationException.
* @param equation
* @throws InvalidEquationException
*/
public QuadraticEquation(String equation) throws InvalidEquationException {
this.coefficient = extractCoefficient(equation);
}
/**
* Builds an equation from given coefficients. May throw InvalidEquationException (e.g., a == 0).
* @param a
* @param b
* @param c
*/
public QuadraticEquation(int a, int b, int c) throws InvalidEquationException {
if (a == 0) {
throw new InvalidEquationException("Not a quadratic equation. First term is required in a quadratic equation.");
}
this.coefficient = new Coefficient(a, b, c);
}
public /* List<Double> */ Answer solve() throws UnsupportedComplexNumber {
/* List<Double> result = new ArrayList<>(); */
int a = coefficient.a, b = coefficient.b, c = coefficient.c ;
double discriminant = b * b - 4 * a * c;
if (discriminant < 0) {
throw new UnsupportedComplexNumber("No real solution.");
} else {
double disc2 = Math.sqrt(discriminant);
/*
result.add((-b - disc2) / 2 / a);
result.add((-b + disc2) / 2 / a);
return result;
*/
double x1 = (-b - disc2) / 2 / a ;
double x2 = (-b + disc2) / 2 / a ;
return new Answer(x1, x2);
}
}
// supporting method.
private /* List<Integer> */ Coefficient extractCoefficient(String equation) throws InvalidEquationException {
Matcher matcher = EQ_PATTERN.matcher(equation.replaceAll("\\s", ""));
if (matcher.matches()) {
/*
List<Integer> r = new ArrayList<>();
for (int i : Arrays.asList(1,3,4)) { // skip group 2. it's a placeholder
try {
r.add(Integer.parseInt(translate(matcher.group(i))));
} catch (Exception e) {
throw new InvalidEquationException("Not a quadratic equation.");
}
}
return r;
*/
int a = Integer.parseInt(translate(matcher.group(1)));
int b = Integer.parseInt(translate(matcher.group(3)));
int c = Integer.parseInt(translate(matcher.group(4)));
return new Coefficient(a, b, c);
} else {
throw new InvalidEquationException("Not a quadratic equation.");
}
}
// supporting method.
private String translate(String str) {
if (str == null) {
return "0";
} else if (str.equals("")) {
return "1";
} else if (str.equals("+")) {
return "+1";
} else if (str.equals("-")) {
return "-1";
} else {
return str;
}
}
```
###### tags: `Interview`