Understand the Card Shop group mission, Amex leadership behaviors, risk mindset, and a 14-day execution roadmap.
Candidate Role Focus: Card Shop Group
At American Express, the Card Shop group sits on the frontline of customer acquisition and engagement. Your code directly impacts millions of users shopping for financial products, card applications, credit offers, and rewards.
Key Expectations for Senior Engineer II:
- End-to-End Ownership: Architect and deliver full-stack features using modern JS, React/Redux, Node.js, and GraphQL.
- Reliability & Risk Mindset: Uphold 99.99% availability, WCAG AA accessibility, low latency (<1.8s LCP), and security.
- Test Automation & SRE: Drive confidence with high unit/integration test coverage and joint SRE incident management.
- Mentorship & Agile Leadership: Lead pair programming, elevate code review rigor, and refine developer workflows.
14-Day Study Plan Roadmap
Deep dive into JS concurrency, React rendering performance, state management, and accessibility (WCAG).
Key Terms Flashcard Revision (Click to Flip)
Event Loop & Microtasks
Event Loop: Coordinates sync code, Call Stack, Microtask queue (Promises, queueMicrotask), and Macrotask queue (setTimeout, I/O). Microtasks execute completely before the next macrotask!
React 18 Concurrent Mode
Concurrent React: Enables non-blocking rendering using useTransition and useDeferredValue. Interruptible rendering allows urgent user inputs to interrupt heavy tree updates.
WCAG 2.1 AA Accessibility
Accessibility: Semantic HTML5 (<main>, <nav>), ARIA attributes (aria-expanded, aria-live), focus management, and keyboard navigation compliance.
Core Web Vitals
LCP (<2.5s), INP (<200ms), CLS (<0.1): Metrics evaluating perceived load speed, user interaction latency, and visual stability for high-converting e-commerce web applications.
Production React 18 Performance & Accessibility Code Pattern
import React, { useState, useTransition, useMemo } from 'react';
// Custom Hook for Card Filter with Non-Blocking Render
export function CardSelectionContainer({ cardList }) {
const [filter, setFilter] = useState('');
const [deferredFilter, setDeferredFilter] = useState('');
const [isPending, startTransition] = useTransition();
const handleFilterChange = (e) => {
const nextVal = e.target.value;
setFilter(nextVal); // Immediate input update
startTransition(() => {
setDeferredFilter(nextVal); // Low-priority list filter
});
};
const filteredCards = useMemo(() => {
return cardList.filter(c => c.name.toLowerCase().includes(deferredFilter.toLowerCase()));
}, [cardList, deferredFilter]);
return (
<div role="region" aria-label="Credit Card Selection">
<label htmlFor="card-search" className="sr-only">Search Cards</label>
<input
id="card-search"
type="search"
value={filter}
onChange={handleFilterChange}
aria-describedby="search-status"
placeholder="Search Amex Cards..."
/>
<span id="search-status" role="status" aria-live="polite" className="sr-only">
{isPending ? 'Filtering card list...' : `${filteredCards.length} cards available`}
</span>
<ul className="card-grid" aria-busy={isPending}>
{filteredCards.map(card => (
<li key={card.id} tabIndex={0}>
<h4>{card.name}</h4>
<p>Annual Fee: ${card.fee}</p>
</li>
))}
</ul>
</div>
);
}
Backend API design, schema definition, DataLoader N+1 query optimization, and high availability middleware.
GraphQL DataLoader & Resolvers (Solving N+1 Problem)
When fetching Card products with associated Member Rewards in GraphQL, a naive resolver initiates 1 query for cards + N queries for rewards. DataLoader batches and caches keys per-request to convert N+1 queries into 2 batched SQL/NoSQL calls!
const DataLoader = require('dataloader');
const { fetchRewardsByCardIds } = require('./services/rewardService');
// Batch function to load rewards for multiple cards in 1 batch query
const rewardBatchLoader = new DataLoader(async (cardIds) => {
const rewards = await fetchRewardsByCardIds(cardIds);
const rewardMap = {};
rewards.forEach(r => { rewardMap[r.cardId] = r; });
return cardIds.map(id => rewardMap[id] || null);
});
const resolvers = {
Query: {
getCardOffers: async (_, { category }, context) => {
return await context.db.cards.find({ category, active: true });
}
},
CardOffer: {
rewardsProgram: (parent, _, context) => {
// High-performance batched call via DataLoader
return rewardBatchLoader.load(parent.id);
}
}
};
module.exports = { resolvers };
Building confidence in deployments with Jest, React Testing Library, SRE incident investigation, and CI/CD pipelines.
Unit & Integration Testing Strategy
Amex Card Shop values test-driven confidence. Code reviews require testing behavior rather than implementation details.
import { render, screen, fireEvent } from '@testing-library/react';
import { CardSelectionContainer } from './CardSelectionContainer';
const mockCards = [
{ id: '1', name: 'Amex Platinum', fee: 695 },
{ id: '2', name: 'Amex Gold', fee: 250 }
];
describe('CardSelectionContainer', () => {
it('renders all cards initially and filters dynamically on user search', async () => {
render(<CardSelectionContainer cardList={mockCards} />);
expect(screen.getByText('Amex Platinum')).toBeInTheDocument();
expect(screen.getByText('Amex Gold')).toBeInTheDocument();
const searchInput = screen.getByPlaceholderText(/search amex cards/i);
fireEvent.change(searchInput, { target: { value: 'Gold' } });
expect(await screen.findByText('Amex Gold')).toBeInTheDocument();
expect(screen.queryByText('Amex Platinum')).not.toBeInTheDocument();
});
});
Designing a high-availability, low-latency Card Selection & Checkout Portal architecture for financial scale.
Architecture Blueprint: Micro-frontend & GraphQL Gateway
Requirements: 10M+ daily visitors, peak traffic during promotional campaigns, <200ms API response time, zero downtime.
Trade-offs & Resiliency Controls:
- Redis Caching: Cache catalog cards for 15 mins with stale-while-revalidate headers.
- Circuit Breakers: Wrap third-party credit check APIs in Hystrix/Opossum circuit breakers to fall back gracefully if external calls fail.
- SRE Telemetry: Emit OpenTelemetry spans to Grafana/Prometheus to isolate latency bottlenecks per GraphQL resolver field.
Structured responses using the STAR method (Situation, Task, Action, Result) aligned with Amex Leadership Behaviors.
Situation: At my previous organization, junior engineers spent 3–4 hours per sprint dealing with redundant UI styling bugs and manual local environment setup, leading to deployment delays.
Task: As Senior Engineer, I was tasked with streamlining developer onboarding, establishing code review standards, and reducing setup friction.
Action: I authored 3 reusable internal npm UI component packages with automated storybook documentation, led weekly pair-programming sessions, and automated environment provisioning using IaC and Docker setup scripts.
Result: Reduced onboarding ramp-up time for new devs from 2 weeks to 3 days, eliminated redundant UI bug tickets by 40%, and boosted team deployment velocity by 83%.
Situation: During a high-traffic promotional campaign, API latency spiked to 4.2 seconds and caused 5xx errors on checkout API endpoints.
Task: Identify root cause, restore service availability immediately, and implement long-term preventive measures.
Action: I joined the emergency incident call with SRE, inspected distributed telemetry logs, identified an unindexed database query combined with a GraphQL N+1 fetch issue, implemented immediate Redis caching fallback, and deployed a patched GraphQL DataLoader resolver.
Result: Reduced latency back under 180ms within 25 minutes, restored 99.99% API availability, and published a post-mortem preventing recurrence across teams.
Self-testing question bank with toggleable model answers for rapid pre-interview revision.
GraphQL vs REST: REST endpoints return fixed data payloads often leading to over-fetching or under-fetching across multiple round trips. GraphQL allows clients to request exact fields in a single HTTP POST call, reducing mobile network bandwidth. However, GraphQL requires careful caching (DataLoader, persisted queries) and schema query complexity depth limits to prevent malicious nested query DDoS attacks.
Optimization Techniques: Code splitting via React.lazy & Dynamic Imports, tree-shaking unused dependencies, image optimization (Next/Image or WebP with explicit dimensions to avoid CLS), SSR/SSG pre-rendering critical above-the-fold content for fast LCP, and deferring non-critical scripts with requestIdleCallback.