cswork / libraryOpen practice workspace

Interview guides · Decskill

Decskill Software Engineer Interview Guide

Decskill Software Engineer interview guide: the three reported rounds, Java, React, Angular and PHP prep, client-interview stories and a 7-day plan.

The 60-second brief

Candidates describe Decskill as a firm that delivers software for a portfolio of clients across different sectors. Engineers are reported to work either on an internal project or inside a client's own infrastructure, so the technology stack and the project context can change from one assignment to the next. The Software Engineer role covers writing and shipping testable code against project requirements, taking part in code reviews and technical documentation, following the team's development workflow, and talking with project managers, technical leads and sometimes the end client.

This guide is for candidates interviewing for a Software Engineer position at Decskill. It covers the three reported rounds, the technical and behavioral questions candidates report (React state management, Java or PHP architecture trade-offs, scalability and maintainability, career transition, stakeholder communication, deadlines), and a seven-day plan. Stack coverage follows what candidates list for the role: Java, React, Angular and PHP, with AWS or Azure, CI/CD and consultancy experience mentioned as nice-to-have.

Candidates report three rounds over roughly 3 to 5 weeks: a screening call with HR, a technical evaluation (a coding test or a deep-dive conversation with specialists), and an interview with the end client. The path can shift with the client project.

Focus areas

  • React
  • Technical Stack Requirements Knowledge
  • Technical Interviewing

Overview

The reported loop mixes two kinds of preparation. One is technical: explaining your primary stack (Java, React, Angular or PHP), reasoning about architectural trade-offs, and showing how you keep code testable and maintainable. The other is professional: telling a clear career story, handling salary and expectation questions, and presenting yourself to a client as someone who can join a project quickly. A candidate who only drills syntax or only rehearses soft-skill answers leaves half the loop uncovered.

Because candidates describe assignments that differ by client, depth in one stack matters less than being able to explain decisions in whatever stack you know best. For every project on your CV, be ready to say what the problem was, what alternatives you rejected, how you tested the change and what you would do differently. The reported example scenarios point the same way: speeding up a slow component, refactoring legacy code, and choosing between a quick fix and a longer-term solution when a client is listening.

Stories are the second asset. Several reported questions are behavioral: why you are changing roles, how you work with cross-functional teams and client stakeholders, how you explained a technical limit to someone non-technical, and how you handled deadlines that moved. Pick four or five real experiences and shape each so it can answer more than one of those prompts. Candidates also report slow feedback after the final stages, so plan to follow up politely instead of waiting in silence.

The Decskill interview process

These are the three stages candidates describe. Details such as whether the technical stage is a coding test or a specialist conversation depend on the client project.

Initial Screening

Candidates describe this as a preliminary call with HR about your background. They report that it centers on your career trajectory, your expectations (salary among them) and your English, with a few high-level technical questions to place your experience. Treat it as a pitch round: have a short, chronological account of your work ready, a clear reason for moving, and numbers you are comfortable stating. Ask what the remaining stages look like for this specific client project, since the path is reported to vary.

What to demonstrate

  • How your background and career direction line up with the role
  • Your reason for changing roles at this point
  • English proficiency and how clearly you communicate
  • Expectations such as salary, availability and remote or hybrid working

How to prepare

  • Write a chronological account of your last two or three roles, ending with why this position, and rehearse it out loud until it flows without notes.
  • Prepare a direct answer to the career-transition question: what you are moving toward, stated without criticizing your current employer.
  • Decide your salary expectation range and your availability before the call, and be ready to state them plainly.
  • List your primary stack and the nice-to-have areas you have touched (AWS or Azure, CI/CD, agency or consulting work) so you can answer a high-level technical question in one or two sentences.

Technical Evaluation

The reported format is either a coding test or a deep-dive interview with specialists, and the page reports that the choice can vary by project. Both versions test your primary stack and how you reason about it. The coding-test version rewards clean, working, tested code; the conversation version rewards being able to give the reasons behind your choices. Reported example scenarios include optimizing a slow component, refactoring legacy code, and explaining how you validate code before production. Think aloud so the reasoning is visible even when the answer is not final.

What to demonstrate

  • Working, readable code if the stage is a practical coding test
  • Depth in your primary language and framework (lifecycle methods, hooks, dependency injection)
  • How you debug, test and validate code before release
  • How you weigh trade-offs such as library or architecture choices

How to prepare

  • Pick one primary stack and refresh its fundamentals: in React, the lifecycle and hooks plus the state-management options; in Java or PHP, the architectural patterns you have actually used and what each cost you.
  • Rehearse the technical questions in this guide aloud: the complex-challenge story, the architecture trade-offs, theory versus daily practice, and scalable plus maintainable code.
  • Prepare a legacy-refactor story and a slow-component story, each with the measurement you used before and after the change.

Client Interview

Candidates describe an interview with the end client, aimed at showing your professional consulting skills. Technical questions can appear, but the setting is client-facing, so how you present decisions to non-engineers carries weight. Reported example: choosing between a quick fix and a long-term architectural solution and putting that choice to a client. Research the client's industry beforehand, tie your past projects to their likely problems, and have questions ready about team structure, development method such as Agile or Scrum, and the hardest technical challenge on the project.

What to demonstrate

  • Professional presence and communication in front of a client
  • Your ability to explain technical choices and limits to non-technical people
  • Interest in the specific project and its context
  • Collaboration habits: code review, version control, working with managers and leads

How to prepare

  • Write a one-paragraph summary of the client's industry and the problems a Software Engineer there might face, and link two of your past projects to it.
  • Prepare the quick-fix versus long-term-solution answer with cost, risk and timeline for each option, ending on a recommendation.
  • Polish three stories: working with stakeholders, explaining a technical limitation, and handling a deadline that moved.
  • Prepare three questions for the client about team structure, development process and the main technical challenge.

Where candidates lose points

Naming hooks, annotations or patterns without ever saying why you picked them

For each technical story, state the problem, the alternative you rejected and what you measured afterward. In React state management, for example, say why a value lived in a store, in Context or in the query cache.

Answering the architecture trade-off question for only one stack or only in the abstract

Choose Java, PHP or your primary framework, name two patterns you have used (layered, MVC, modular monolith, service-based), and give a cost each one caused in a real project, plus when you would use the other.

Pitching a long-term rewrite to a client with no cost, risk or interim plan

Present the quick fix and the lasting fix side by side with effort, risk and what the client sees in each case, then recommend one. Say how you would record and schedule the follow-up work if the quick fix is chosen.

Behavioral stories told as "we did" with no personal action or result, or a transition answer that criticizes the current employer

Keep four STAR stories with your own decision and a visible outcome, and rehearse the career-move answer as a pull toward specific work rather than a push away from a current job.

Treating the HR call as a formality and being unprepared on salary, availability and English

Decide your range, notice period and work arrangement beforehand, and practice stating them in clear spoken English. Candidates report that this call covers expectations and communication, not only your CV.

Questions & practice

Track a rolling failure rate per destination for circuit decisions

Easy · sliding window · ring buffer · circuit breaker

The egress service delivers about 1,500 webhooks per second across roughly 40,000 destinations, each call bounded by a 10 second timeout. Maintain, per destination, the failure rate over the trailing 60 seconds so a caller can ask before dispatch whether the circuit should open. Attempts arrive as (destination_id, finished_at_ms, outcome). Requirement: amortised O(1) per attempt, with total memory bounded by the destination count rather than by traffic. Give the structure, its exact memory, and the rule that stops a destination with three attempts from opening a circuit.

Approach

  1. Name the exact-deque version and then reject it as the default. Holding timestamps and advancing a tail pointer past anything older than now minus 60 seconds is a correct two-pointer window at amortised O(1) per attempt, but its memory tracks in-window traffic, so one destination in a retry storm holds hundreds of thousands of entries while thousands of quiet destinations hold none.
  2. Use a ring of 60 one-second buckets per destination, each bucket a pair of counters for attempts and failures. On an attempt, advance the ring by the elapsed whole seconds, zeroing at most min(elapsed, 60) buckets, then increment the head. That is amortised O(1) with a fixed footprint per destination.
  3. State the footprint: 60 buckets times two 4-byte counters is 480 bytes of payload per destination, so 40,000 destinations is roughly 20 to 25 MB with per-entry overhead, bounded by the catalogue rather than by the rate. The cost is granularity, since the oldest bucket ages out in whole seconds, which is far tighter than the decision needs.
  4. Require a minimum sample before the circuit may open. A destination with three attempts and three failures reads as 100 percent and is not evidence; a floor of roughly 20 attempts in the window makes the ratio meaningful, and below that floor use a run of consecutive failures as the trigger instead.

Follow-up

  • The fleet is 30 instances and each sees roughly a thirtieth of a destination's traffic. Where does the rate actually live, and what does a per-instance answer get wrong?
  • A destination answers in 9.5 seconds and succeeds. It is not failing but it is consuming your per-destination concurrency. What signal should open the circuit here?

Find overlapping job attempts and peak concurrency from lease records

Medium · sweep line · intervals · leases

A day of job_run history yields about 50,000,000 attempt records: (job_run_id, job_type, attempt, started_at, finished_at which is NULL when the worker died, lease_expires_at). Leases expire on a clock, so a job that outran its lease ran twice. Produce (a) every job_run_id whose attempts overlapped in wall-clock time and (b) the peak number of simultaneously running attempts per job_type with the minute it occurred. Target O(n log n). State how you treat a NULL finished_at and what clock skew does to your answer.

Approach

  1. Define the interval before sorting anything: an attempt occupies [started_at, COALESCE(finished_at, lease_expires_at)). finished_at is observed and lease_expires_at is only a promise, so every attempt without a finish contributes an estimate and the whole result is a lower bound on overlap rather than an exact count.
  2. For peak concurrency, sweep: emit 2n endpoints, sort by (timestamp, kind) with ends ordered before starts at equal timestamps, then walk the sequence maintaining a counter per job_type and record each type's maximum with its timestamp. O(n log n) dominated by the sort, O(n) space, or O(1) extra if the sort is external and the walk streams.
  3. For overlap detection, do not compare attempts pairwise. A single global sort by (job_run_id, started_at) gives both the grouping and the order; within a group, keep the maximum end seen so far and report an overlap exactly when the next start is less than that running maximum, which is one linear pass after the sort.
  4. Half-open intervals matter and are easy to get wrong: with closed intervals an attempt ending at the same millisecond another begins reads as concurrency two, and across 50,000,000 records that artefact swamps the real signal.

Follow-up

  • A handler is not idempotent and you have found 400 overlapping jobs. Which of them actually caused damage, and what would you query to find out?
  • Peak concurrency for one job_type is 4 against a configured cap of 4. Is the cap working, or is the data hiding attempts that never started?

Canonicalise a request body into a stable idempotency fingerprint

Medium · parsing · canonicalisation · hashing

idempotency_key.request_fingerprint is a SHA-256 over the method, path and canonicalised body, and a retry whose fingerprint differs must be rejected with 422 rather than served the stored response. Write the canonicaliser. Bodies are JSON up to 256 KB nested at most 32 levels; clients vary key order, whitespace and unicode escaping, and some send 64-bit ids as JSON numbers. Produce a deterministic byte string such that semantically identical bodies match and any semantic difference does not. State your complexity and name two normalisations you refuse to perform.

Approach

  1. Parse once into a tree, then re-serialise under fixed rules: object keys sorted, array order preserved, one escaping convention, no insignificant whitespace. Parsing is O(n) and sorting keys is O(k log k) per object, so O(n log n) overall with O(depth) stack, and the 32-level cap is enforced during parsing because hostile nesting is how a canonicaliser becomes a stack overflow.
  2. Sort keys by their UTF-8 bytes and say why the obvious implementation is wrong in some runtimes: a default string comparison that orders by UTF-16 code units places surrogate pairs, meaning code points from U+10000 up, below U+E000 to U+FFFF, which is not UTF-8 byte order, so two services written in different languages disagree on the same document.
  3. Do not re-encode numbers through a double. IEEE-754 binary64 represents integers exactly only up to 2^53, so normalising a 19-digit id through a float changes it, and 1 against 1.0 cannot be reconciled without deciding whether they are the same value. Preserve the literal token, and require ids as strings at the API boundary if you want them comparable.
  4. Reject duplicate keys rather than picking one. JSON permits them and parsers disagree, most keeping the last, so any choice you make ties the fingerprint to a parser detail that the code handling the request does not necessarily share.

Follow-up

  • A client sends the same logical request with an extra field your API ignores. Same key, different fingerprint, so you return 422. Is that the right answer?
  • Where does the fingerprint get computed relative to request decompression and the body-size limit?

Keep soft-deleted accounts from blocking re-registration

Easy · soft delete · unique constraints · engine differences

app_user holds user_id, tenant_id, email CITEXT, password_hash (NULL for SSO principals), email_verified_at, auth_version, status ('invited','active','suspended','deactivated'), created_at, updated_at, deleted_at. Two live accounts for one address inside a tenant must be impossible, but an address freed by a soft delete must be reusable, and the same tenant may delete and re-register it repeatedly. Write the uniqueness DDL for PostgreSQL 16, then the equivalent for MySQL 8 where partial indexes do not exist, and say what each permits once three deleted rows already hold that address.

Approach

  1. Start from what is actually unique: not (tenant_id, email), but (tenant_id, email) among live rows. PostgreSQL says that directly — CREATE UNIQUE INDEX app_user_live_email ON app_user (tenant_id, email) WHERE deleted_at IS NULL. A full constraint over the same two columns burns the address permanently the first time someone deletes an account.
  2. Keep case-insensitivity in the type or the index, never in the application: CITEXT as given, or UNIQUE (tenant_id, lower(email)) as an expression index where the extension is unavailable. A case-sensitive unique column is exactly how two accounts for one human appear.
  3. For MySQL 8 the predicate has to move inside the key: add a discriminator column that is a constant 0 while the row is live and is set to user_id on delete, with UNIQUE (tenant_id, email, deleted_marker). Live rows share the constant and still collide; deleted rows differ from each other and stop colliding.
  4. State the NULL variant and its dependency: leaving the marker NULL for deleted rows also works, because a unique index treats NULLs as distinct — true in MySQL, and true in PostgreSQL only under the default NULLS DISTINCT, which PostgreSQL 15 lets you reverse. Check the polarity against the three existing deleted rows: constant-on-live is what preserves the collision you want, and reversing it silently admits duplicate live accounts.

Follow-up

  • A deleted account re-registers with the same address the next day. Do the old resource rows follow the new user_id, and how does the API keep the two principals apart?
  • How do you honour an erasure request while resource_revision.actor_user_id still references this table?

Stop tag and share joins from fanning out a page

Medium · join fan-out · semi-joins · many-to-many

resource_tag is (resource_id, tag_id) with PK (resource_id, tag_id); resource_share is (resource_id, shared_with_user_id, permission). The tagged-and-shared listing inner-joins resource to both, filters tenant_id, tag_id = ANY($2) and shared_with_user_id = $3, orders by updated_at DESC and takes 50. Pages come back with fewer than 50 distinct resources and the total in the header is far too high. Explain the row multiplication, rewrite both the page query and the count query so each is correct, and name the index each one needs. PostgreSQL 16.

Approach

  1. Do the arithmetic against the predicates that are actually there. An inner join emits one row per matching child row, and both joins are filtered: tag_id = ANY($2) admits only the requested tags, shared_with_user_id = $3 admits one user's share rows. So a resource holding three of the requested tags and shared with $3 once yields three rows, not one — the multiplier is its count of matching tags times its share rows for that single user, and that second factor is 1 unless the table admits duplicate (resource_id, shared_with_user_id) pairs. LIMIT 50 then limits rows rather than resources, and COUNT(*) counts pairs — the header is the product, not the population.
  2. Reject DISTINCT as the fix. It deduplicates after the product has been built, so the planner must materialise and sort the fanned-out set before the LIMIT can apply, and it leaves any SUM or AVG in the same select list wrong.
  3. Rewrite both filters as semi-joins, keeping resource as the only row source: AND EXISTS (SELECT 1 FROM resource_tag rt WHERE rt.resource_id = r.resource_id AND rt.tag_id = ANY($2)) and the same shape against resource_share. A semi-join stops at the first match per resource and preserves the driving index order, so ORDER BY updated_at DESC, resource_id DESC LIMIT 50 still stops after 50 rows.
  4. Count with the same predicates and no join at all: SELECT count(*) FROM resource r WHERE r.tenant_id = $1 AND r.status = 'active' AND EXISTS (...) AND EXISTS (...). Nothing multiplies a resource, so the number is the population.

Follow-up

  • The filter changes from 'any of these tags' to 'all of these tags'. Rewrite it and state what it costs relative to the ANY form.
  • A resource can be shared with the same user twice under different permissions. Does your count change, and should it?

Can you walk us through a complex challenge you solved using your primary programming language?

Medium · Technical Proficiency

Approach

  1. Choose one problem where the language itself mattered, not just the business logic: for example a Java service starving its thread pool because blocking I/O ran inside CompletableFuture's default ForkJoinPool.commonPool, or a PHP import hitting memory_limit that I fixed by streaming rows through a generator (yield) instead of loading the whole file into an array.
  2. Open with the symptom and how I measured it (heap dump, profiler, slow-query log, p95 latency), then name the root cause in one sentence. Without a baseline number the result in the story cannot be checked.
  3. Explain the fix through the language mechanism: a dedicated bounded executor, JOIN FETCH or an entity graph to remove a Hibernate N+1, a generator to keep memory flat, or useMemo/React.memo after the React Profiler showed which component was re-rendering.
  4. Give the before/after numbers and the regression test or monitoring I added so the fix stayed in place, then name one alternative I rejected and why (a larger pool or a raised memory limit only hides the cause).

Follow-up

  • How did you confirm that the root cause was the one you fixed and not a coincidence?
  • What would you change if the data volume grew tenfold?
  • How did you explain the fix to the rest of the team or in code review?

What are the trade-offs between different architectural patterns in Java or PHP?

Medium · Technical Proficiency

Approach

  1. Name the patterns before comparing them: layered (controller, service, repository), MVC as in Spring MVC, Laravel or Symfony, hexagonal (ports and adapters), and modular monolith versus microservices. Then compare each on testability, coupling, team size and operational cost.
  2. Layered is quick to learn but tends to leak business rules into controllers or produce an anemic domain. Hexagonal keeps the domain free of framework and database code and makes unit tests easy, but costs extra interfaces and mapping code.
  3. Persistence style is a real trade-off in this stack. Active Record (Laravel's Eloquent) is fast to write for CRUD but ties entities to tables. Data Mapper (Doctrine, JPA/Hibernate) separates the model from storage at the cost of more configuration and lazy-loading pitfalls.
  4. Runtime model changes the answer. PHP-FPM is shared-nothing: each request starts fresh, so cross-request state goes in Redis or the database. A long-running JVM keeps connection pools and in-memory caches, which helps throughput but brings memory and concurrency concerns.
  5. Microservices give independent deploys and scaling but add network failures, distributed transactions (sagas, the outbox pattern), tracing and more pipelines. I would start with a modular monolith with enforced module boundaries and split only when a module needs a separate deploy cadence or separate scaling.

Follow-up

  • How would you keep data consistent when an order spans two services?
  • When have you seen hexagonal architecture turn out to be over-engineering?
  • How would you enforce module boundaries inside a monolith?

Can you explain the difference between theoretical concepts and their practical implementation in your daily w

Medium · Technical Proficiency

Can you explain the difference between theoretical concepts and their practical implementation in your daily workflow?

Approach

  1. Read the question as a request for concrete gaps between textbook and production, and give two or three examples, each with the theory, what happened in practice, and the evidence that settled it.
  2. Complexity versus constant factors: LinkedList advertises O(1) insertion, but only once you hold the node, and reaching a position is O(n). ArrayList's contiguous memory is cache-friendly, so it usually wins in Java, and a quick JMH benchmark shows it.
  3. Design principles versus delivery: SOLID and DRY are guides, not quotas. I tell how I removed an interface that had only one implementation, or kept two similar functions apart because they change for different reasons, and how the code review settled it.
  4. Normalisation and testing theory: third normal form is my default, but I added a denormalised read table or cached column when EXPLAIN showed join cost on a hot path. For tests, the pyramid is a guide, and I added integration tests against a real database where mocks had hidden SQL bugs.
  5. End with my rule: I apply the theory by default and deviate only when a measurement or a real constraint (deadline, team skill, client requirement) justifies it, and I record that reason in the PR or an ADR.

Follow-up

  • Give an example where following the theory strictly would have been the better call.
  • How do you decide when a measurement is good enough to justify breaking a convention?
  • How do you pass these judgement calls on to a junior developer?

How do you ensure your code is both scalable and maintainable in a production environment?

Medium · Technical Proficiency

Approach

  1. Treat it as two problems. Maintainability is about how cheaply code can change. Scalability is about how it behaves as load and data grow. Give concrete practices for each instead of a general statement about clean code.
  2. Maintainability: small modules with clear boundaries, names from the business domain, unit tests on domain logic, integration tests against a real database (for example Testcontainers), static analysis in CI (SonarQube, PHPStan, ESLint) and code reviews that check behaviour and readability, not only style.
  3. Scalability: keep services stateless so they scale horizontally behind a load balancer, with sessions in an external store. Check indexes with EXPLAIN, remove N+1 queries, use keyset rather than OFFSET pagination on large tables, move slow work to a queue, and cache with an explicit invalidation rule.
  4. Observability ties the two together: structured logs, p95/p99 latency and error-rate metrics, and tracing across calls. Then a scaling decision rests on a measured bottleneck, not a guess. I avoid premature optimisation and make the hot path the exception.
  5. For CI/CD (listed as a nice-to-have), automated tests and a small-batch deploy pipeline with rollback make frequent change safe. A feature flag or a backward-compatible database migration (expand, then contract) lets me ship without downtime.

Follow-up

  • How would you find the bottleneck if an endpoint slows down only in production?
  • Why does OFFSET pagination degrade on large tables, and what replaces it?
  • How do you handle a team that disagrees on code standards in review?

Listing latency scales with page size, not with filters

Easy · n+1 · latency · query batching

The tenant listing endpoint reads resource filtered by tenant_id and status, ordered by updated_at DESC, and returns each row plus the owner's display name from app_user and the actor of that resource's latest resource_revision. p99 is 55 ms at 10 rows per page and 1.4 s at 200. Database telemetry shows 401 statements per request, each under 1 ms, and nothing in the slow-query log. Diagnose the cause and give the fix, stating the statement count per request and the p99 you expect afterwards.

Approach

  1. Read the counters before forming a theory. 401 statements for 200 rows is one driver query plus two per row, and sub-millisecond execution with an empty slow-query log rules out a bad plan. The time is round trips, which is why it is invisible in every per-query metric and scales with rows returned rather than with filter selectivity.
  2. Name the two per-row statements from their normalised text: a single-row app_user lookup by user_id, and a resource_revision lookup by resource_id ordered by version DESC LIMIT 1. Confirm by dropping those two response fields and watching the statement count fall to one. That locates the calls in the serialisation layer, not the repository.
  3. Check that the arithmetic accounts for the whole gap. Measure one round trip to the replica in isolation; 400 trips at roughly 3 ms of network plus 0.2 ms of execution is about 1.3 s on top of a 55 ms baseline, which matches. If the multiplication had fallen short, the N+1 would only be part of the story and you would keep looking.
  4. Batch both lookups. Collect owner_user_ids and resource_ids from the driver query, then issue WHERE tenant_id = $1 AND user_id = ANY($2) for the users, and PostgreSQL's SELECT DISTINCT ON (resource_id) ... WHERE resource_id = ANY($2) ORDER BY resource_id, version DESC for the latest revision, which the UNIQUE (resource_id, version) index serves directly. On an engine without DISTINCT ON, use a lateral join or a row_number window. Three statements per request at any page size.

Follow-up

  • The page size is capped at 200 today. What breaks first if it is raised to 2,000, and is it still this bug?
  • How do you stop the next N+1 from reaching production, given that no individual query is slow and the endpoint's tests pass?

Suggested practice checklist

The plan follows the reported loop: HR screening material first, then your primary stack and the reported technical questions, then coding drills, then the client interview and stories, ending in a full dry run.

Day 1 — Map the loop and your project inventory

  • Write the three rounds (HR screening, technical evaluation, client interview) and for each list what you think it covers; mark the one you are least ready for.
  • List four or five projects from your CV with the stack, your role, one hard decision and one measurable result for each.
  • Pick your primary stack among Java, React, Angular and PHP and list its fundamentals that you would struggle to explain.

Deliverable: A one-page loop map plus a project inventory table naming the primary stack and the weakest round.

Day 2 — Primary-stack depth and the complex-challenge story

  • Refresh the framework internals you would be asked about: lifecycle and hooks in React, dependency injection in your Java or PHP framework, or the Angular equivalent.
  • Write out the answer to the complex-challenge question using one project from your inventory, including the options you rejected.
  • Write and answer aloud the architecture trade-off question for your own stack, naming two patterns and one real cost of each.

Deliverable: A written complex-challenge story and a spoken architecture trade-off answer for your stack.

Day 3 — React state management, built and explained

  • Build a small screen that shows one list in three ways: component state, Context with a reducer, and a server-state cache, and note how each behaves on a mutation.
  • Add a deliberate bug (a context that re-renders everything, or a stale closure in an effect) and find it with the React profiler or logging.
  • Practice the spoken answer: kinds of state, the escalation path, the pitfalls, and one story from your own work.

Deliverable: A small working comparison project and a rehearsed spoken answer to the React state management question.

Day 4 — Production quality: theory versus practice, scalable, maintainable

  • Describe two places where textbook advice did not survive your daily workflow and what you did instead.
  • Write a checklist for scalable and maintainable code in your stack: tests, code review habits, logging, module boundaries and performance measurement.
  • Prepare the legacy-refactor story and the slow-component story, each with a before and after measurement.

Deliverable: A written checklist and two refactor or performance stories, each with a number or observable result.

Day 5 — Coding test practice

  • Review your solutions for naming, edge cases and tests, as a reviewer would.

Deliverable: Two solved coding drills and one debugging write-up, each with the tests you wrote.

Day 6 — Screening answers and client stories

  • Write the career-transition answer in past, present, future shape, then say it aloud without notes.
  • Write four STAR stories (stakeholders, explaining a technical limitation, deadline pressure, a shifting priority) and mark which prompts each can serve.
  • Decide your salary range, notice period and availability, and practice stating them.

Deliverable: A spoken transition answer, four STAR stories and a note with your expectations.

Day 7 — Dry run of the client interview

  • Role-play the client round with a friend: ten minutes of project talk, the quick-fix versus long-term-solution question, and a stakeholder explanation of a technical limit.
  • Research the industry of a likely client and prepare three questions on team structure, methodology and the hardest technical challenge.
  • Plan your follow-up message for after the final stage, since candidates report slow feedback.

Deliverable: A completed mock with notes on what to fix, three client questions and a follow-up message.

Behavioural preparation

Candidates report that Decskill's behavioral questions concern why you are changing roles, how you work with cross-functional teams and client stakeholders, how you explain technical limits to non-technical people, and how you cope with tight or shifting deadlines. For a role that can sit inside a client's organization, the stories should show your own decisions and how you communicated them.

  1. Tell a story about learning a new framework or tool quickly to deliver on a project.
  2. A client wants a quick fix but you believe a lasting fix is needed: how do you put the choice to them?

How do you handle state management in a modern frontend environment like React?

Medium · Technical Proficiency

Approach

  1. Frame state by kind before naming tools. I separate local UI state (a toggle, an input value) that stays in useState or useReducer in the component, shared client state that several distant components read, server state fetched from an API, URL state such as filters and page number, and form state. Each kind gets the lightest tool that fits.
  2. Cover the escalation path. Start local, lift state to the nearest common parent when two siblings need it, use Context for low-frequency values like the theme or signed-in user, and reach for a store such as Redux Toolkit or Zustand when many components share frequently changing state and you need predictable updates and devtools.
  3. Treat server data as a cache, not as global state. A data-fetching library such as TanStack Query or RTK Query handles loading and error flags, deduplicated requests, background refetching and invalidation after a mutation, which removes most of the hand-written effect and reducer code.
  4. Name the pitfalls: Context re-renders every consumer when its value changes, so split contexts or memoize the value; copying props into state creates two sources of truth; mutating state in place breaks change detection; effects with missing dependencies cause stale closures; unguarded fetches in effects cause race conditions on fast navigation.
  5. Close with a real example from your own work: what state lived where, which choice you changed after a problem appeared (for example, a context that re-rendered a large tree), and how you confirmed the improvement with the React profiler.

Follow-up

  • When would you pick Redux or a similar store over Context plus useReducer?
  • How do you stop a state change from re-rendering a large part of the tree?
  • How do you keep a list on screen consistent after a mutation succeeds on the server?

Why are you looking to transition into a new role at this stage of your career?

Medium · Behavioral and Professional Alignment

Approach

  1. Use a past, present, future shape. Past: what you built and learned in the current or last role. Present: what has run its course, stated as a fact about your growth (for example, you have worked mostly in one stack and want exposure to varied projects). Future: what you are moving toward and why this position serves it.
  2. Make the reason a pull, not a push. Never criticize a manager, team or employer. Frame it as a specific thing you want more of, such as client-facing work, different stacks or broader project exposure, only if it is true for you; interviewers can tell a rehearsed motive from a real one.
  3. Tie it to the role as candidates describe it: assignments across different clients and stacks, working with stakeholders, and learning new frameworks quickly. Back the claim with one concrete example of picking up a new technology under a deadline.
  4. Handle the timing part directly. If the question hints at career stage (changing late, early or after a short tenure), address it in one sentence with the honest reason and move on to what you will deliver. Avoid vague answers such as wanting a new challenge with no example.
  5. Keep it short and finish by handing the conversation back with a concrete topic about the role, so the answer leads into the next question instead of trailing off.

Follow-up

  • What would make you leave this role as well?
  • What are you not looking for in your next position?
  • How does this move fit where you want to be in a few years?

How do you approach working with cross-functional teams and client stakeholders?

Medium · Behavioral and Professional Alignment

Approach

  1. Choose one project where you dealt with at least three groups, for example a project manager, a technical lead and a client contact, and state your own role in one sentence. Use STAR, and keep every action in the first person singular so your contribution is clear.
  2. Show the mechanics of how you worked: shared written acceptance criteria before building, short demos instead of one big reveal, a regular status update to the client, and a single place where decisions and scope changes were recorded.
  3. Include one point of friction. For example, the client asked for a change that conflicted with the plan; you sized the change, laid out what would slip, and let the owner choose. Showing how you handled disagreement with evidence matters more than a story where everyone agreed.
  4. Describe how you translate between audiences: technical detail for the lead, impact and dates for the manager, outcome and options for the client. Mention the habit of raising a risk early rather than at the deadline.
  5. Finish with the result and one lesson, such as a lighter review step or an earlier demo cadence that you introduced and kept using.

Follow-up

  • Tell me about a time a client asked for something outside the agreed scope.
  • How do you handle a disagreement with a project manager over priorities?
  • What do you do when a stakeholder goes silent on a decision you need?

Can you describe a time you had to explain a technical limitation to a non-technical stakeholder?

Medium · Behavioral and Professional Alignment

Approach

  1. Pick a real limitation that had a business consequence, such as an API rate cap, a legacy system that could not support a feature in the requested time, or a browser or device constraint. State the situation in two sentences and name who the stakeholder was.
  2. Show the translation. Replace technical terms with impact: what the user or business would see, what it would cost in time or money, and what risk it carried. Mention an analogy or a diagram only if you actually used one.
  3. Present options, not just a refusal: for example, a reduced version delivered on time, the full version on a later date, or a different approach with trade-offs spelled out. Say which one you recommended and why.
  4. Cover how you checked understanding (asking them to restate the decision, or confirming it in writing afterward) and how you handled pushback without becoming defensive or giving in to something unsafe.
  5. State the outcome and one thing you changed afterward, for example flagging constraints earlier in planning. A story where you simply said no, or one where the stakeholder never understood, is the version to avoid.

Follow-up

  • What did you do when the stakeholder disagreed with your recommendation?
  • How did you know they understood the limitation and its consequences?
  • Would you raise it differently if you found out sooner?

How do you handle tight deadlines and shifting project priorities?

Medium · Behavioral and Professional Alignment

Approach

  1. Start with how you establish priority when it moves: ask the decision-maker for the single most important outcome, write down what is in and out, and make the trade-off among scope, time and quality explicit rather than quietly working longer hours.
  2. Describe the technical tactics you used: slicing the work into a smaller deliverable that still works end to end, keeping tests on the critical path, using feature flags so unfinished work can ship dark, and keeping pull requests small so review does not become the bottleneck.
  3. Show communication. When priorities shifted, you told the project manager and client what slipped, in writing, and gave an updated date instead of a surprise at the end of the sprint.
  4. Address the quick-fix-versus-proper-fix tension. If you shipped a shortcut to meet a date, say that you logged the debt, created a follow-up ticket and agreed when it would be repaid.
  5. Give the result and a limit: what shipped, what was cut, and a case where you pushed back or asked for more time because the risk was too high. A story that only says you worked weekends shows no judgment.

Follow-up

  • Priorities changed in the middle of a sprint: what did you drop, and who agreed?
  • What did you do about the shortcuts you took to hit the date?
  • When have you said that a deadline was not realistic, and what happened?