Interview prep

C# and .NET interview questions, answered properly

Sixty questions that come up again and again in interviews for C# and .NET roles, from junior to senior. Each has a direct answer you could give out loud, and a link to the lesson that explains it fully. Written for people who want to understand the answer, not memorise it.

How to use this page. Read a question, answer it in your own words before opening the answer, then compare. If your answer was vague, follow the "Go deeper" link. The interviewers you want to impress are listening for the why, and the lessons are where the why lives.

Topics
  1. How .NET interviews actually go
  2. C# language fundamentals
  3. OOP and design
  4. Collections, generics and LINQ
  5. Async and concurrency
  6. Memory and the runtime
  7. ASP.NET Core
  8. Entity Framework Core and data
  9. Architecture and distributed systems
  10. Testing
  11. Production debugging
  12. A one-week revision plan

How .NET interviews actually go

Most processes have three or four stages: a short screen (often with the questions in the first two sections below), a technical interview that mixes conceptual questions with a coding exercise, a system-design conversation for mid-level and senior roles, and a behavioural round. The technical rounds tend to probe the same areas, because those are where shallow knowledge is easiest to expose: value versus reference semantics, async, memory, LINQ deferred execution, and dependency-injection lifetimes. If you are short on time, revise those five first.

A good answer has three parts: what it is, why it exists, and where it goes wrong. "Async lets a method release its thread while waiting on I/O; it exists so a server can handle thousands of concurrent requests with a small thread pool; it goes wrong when someone blocks on .Result and deadlocks the context." Aim for that shape.

C# language fundamentals

1. What is the difference between a value type and a reference type?

A value type (int, double, bool, struct, enum) holds its data directly; copying it copies the data. A reference type (class, string, arrays, delegates) holds a reference to an object; copying it copies the reference, so two variables point at the same object. This is why changing a property through one class variable is visible through another, and why the same operation on a struct is not.

Go deeper: Value vs Reference Types →
2. When would you choose a struct over a class?

When the type is small, represents a single value (a point, a money amount, a date), is immutable, and is created in large numbers — because structs avoid a heap allocation and are cheap to copy. Choose a class when the type has identity, is large, is mutated, or needs inheritance. record struct gives you value semantics with equality and deconstruction for free.

Go deeper: Structs →
3. Why are strings immutable, and what should you use to build one in a loop?

A string can never change after creation; every "modification" produces a new string. Immutability makes strings safe to share, cache and use as dictionary keys. Concatenating in a loop therefore allocates a new string on every iteration; use StringBuilder, or string interpolation and string.Join for one-shot builds.

Go deeper: Strings and Text →
4. What is boxing, and why does it matter?

Boxing is wrapping a value type in an object on the heap so it can be treated as a reference (object o = 42;). Unboxing is the reverse cast. It matters because each box is a heap allocation and a copy, so code that boxes in a hot loop — classically, non-generic collections, or passing a struct as object or as an interface — can be dramatically slower than the generic equivalent.

Go deeper: Boxing and Unboxing →
5. What is the difference between == and .Equals()?

For reference types, == compares references unless the type overloads it (string does, comparing content). .Equals() is virtual and can be overridden to compare values. If you override Equals you must also override GetHashCode so that equal objects hash equally, or dictionaries and sets will misbehave. Records implement both for you.

Go deeper: Equality and Hashing →
6. const versus readonly versus static readonly?

const is a compile-time constant baked into every assembly that uses it, so changing it requires recompiling consumers; it works only for primitives and strings. readonly is an instance field set once, in the declaration or constructor, at runtime. static readonly is a single runtime-initialised value shared by all instances — the right choice for things like a shared HttpClient or a computed table.

Go deeper: Variables and Constants →
7. What do ref, out and in do?

All three pass a parameter by reference instead of by value. ref requires the caller to initialise it and allows the callee to read and write. out requires the callee to assign it before returning — the TryParse pattern. in passes a read-only reference, used to avoid copying large structs without allowing modification.

Go deeper: ref, in, out →
8. What are nullable reference types, and what does ! do?

With nullable reference types enabled, string means "never null" and string? means "may be null", and the compiler warns when you dereference something that might be null. The null-forgiving operator ! tells the compiler "I know this is not null here" and suppresses the warning — it does not check anything at runtime, so if you are wrong you still get a NullReferenceException.

Go deeper: Nullable Reference Types →
9. What are records, and how do they differ from classes?

A record is a reference type (or, with record struct, a value type) with compiler-generated value equality, a readable ToString, deconstruction, and non-destructive mutation with with. Two records with the same property values are equal; two class instances are not. Use records for data that is defined by its contents — DTOs, messages, immutable domain values — and classes for objects with identity and behaviour.

Go deeper: Records and Record Structs →
10. What is pattern matching in C#?

A set of features for testing a value's shape and extracting from it in one step: type patterns (if (x is Customer c)), property patterns ({ Status: Active, Total: > 100 }), relational and logical patterns, list patterns, and switch expressions that return a value. It replaces chains of casts and null checks with declarative code the compiler can check for exhaustiveness.

Go deeper: Pattern Matching →

OOP and design

11. Abstract class or interface?

An interface describes a capability (IDisposable, IComparable<T>) and a type can implement many. An abstract class describes an incomplete "is-a" base with shared state and implementation, and a type can inherit only one. Since C# 8 interfaces can carry default implementations, so the practical rule is: prefer interfaces for contracts, and reach for an abstract class only when derived types genuinely share fields or constructor logic.

Go deeper: Abstract Classes →
12. What is the difference between virtual/override and new?

override replaces a virtual member polymorphically: calling it through a base-type reference runs the derived version. new hides the base member instead: which version runs depends on the compile-time type of the reference, not the runtime object. new is almost always a mistake in application code; if you find yourself wanting it, the base member should probably be virtual.

Go deeper: Overloading and Overriding →
13. Why prefer composition over inheritance?

Inheritance couples a derived type to every implementation detail of its base, so a change to the base can silently break subclasses, and a class can only inherit from one parent. Composition — holding a reference to a collaborator and delegating to it — lets you combine behaviours freely, swap them at runtime, and test them in isolation. Inherit when there is a genuine "is-a" relationship and the base is designed for it; compose otherwise.

Go deeper: Composition vs Inheritance →
14. Explain SOLID in one line each.

Single responsibility: a class has one reason to change. Open/closed: extend behaviour without modifying existing code (usually via abstractions). Liskov substitution: a derived type must be usable wherever its base is expected, without surprises. Interface segregation: many small interfaces beat one large one. Dependency inversion: depend on abstractions, and let high-level policy own them, not the low-level details.

Go deeper: SOLID Principles →
15. What does sealed do, and why would you use it?

sealed on a class prevents inheritance; on an override it prevents further overriding. Use it to state that a type is not designed as a base — which is most types — and because the JIT can devirtualise calls on sealed types, which is a small but free performance win.

Go deeper: Sealed Classes and Members →
16. What is dependency inversion, and how does it relate to dependency injection?

Dependency inversion is the design principle: high-level code should depend on abstractions it owns, not on concrete low-level implementations. Dependency injection is the mechanism that makes it practical: instead of a class constructing its dependencies, they are passed in, usually by a container that resolves the object graph. DI without inversion (injecting concrete types) misses the point; inversion without DI leaves you wiring factories by hand.

Go deeper: Dependency Inversion →

Collections, generics and LINQ

17. Array, List<T> or LinkedList<T>?

An array is fixed-size with O(1) indexing and the lowest overhead. List<T> is a growable array: O(1) indexing and amortised O(1) append, with the occasional resize copy. LinkedList<T> gives O(1) insert and remove at a known node but O(n) indexing and poor cache behaviour, so it is rarely the right choice in practice. Default to List<T>.

Go deeper: Lists →
18. How does Dictionary<TKey,TValue> work, and what is the GetHashCode contract?

A dictionary hashes the key to pick a bucket, then compares with Equals within the bucket, giving average O(1) lookup. The contract: objects that are Equals must return the same GetHashCode, and the hash must not change while the object is a key. Mutating a key's hash-relevant fields after insertion makes the entry unreachable — a classic bug with mutable classes used as keys.

Go deeper: Dictionary Internals →
19. IEnumerable<T> versus IQueryable<T>?

Both represent a lazily evaluated sequence, but IEnumerable<T> operators run in memory over objects, while IQueryable<T> operators build an expression tree that a provider (such as EF Core) translates — typically into SQL — and runs elsewhere. Calling .ToList() or .AsEnumerable() on a queryable draws the line: everything after it runs in your process, over whatever was fetched.

Go deeper: IEnumerable and IQueryable →
20. What is deferred execution, and what bug does it cause?

Most LINQ operators do no work when called; they return a query that runs when enumerated. So a query can run once per foreach, once per .Count(), and again per .First() — repeating a database call or an expensive computation each time, and reflecting changes to the source between enumerations. The fix is to materialise once with .ToList() or .ToArray() when you will use the result more than once.

Go deeper: Deferred Execution →
21. What does yield return do?

It turns a method into an iterator: the compiler generates a state machine that produces one element each time the consumer asks, pausing the method between elements. This lets you build lazy, potentially infinite sequences and pipelines without allocating intermediate collections, and is how many LINQ operators are implemented.

Go deeper: IEnumerable<T> Internals →
22. What are generic constraints, and why use them?

Constraints (where T : class, where T : IComparable<T>, where T : new(), where T : struct, where T : INumber<T>) tell the compiler what a type parameter can do, so the generic code can call those members and callers cannot supply an unsuitable type. Without a constraint, T is treated as object, which is why T a, b; return a < b; does not compile until you constrain T.

Go deeper: Generic Constraints →
23. Explain covariance and contravariance.

Covariance (out T) lets you use IEnumerable<Dog> where IEnumerable<Animal> is expected, because the interface only produces T. Contravariance (in T) lets you use IComparer<Animal> where IComparer<Dog> is expected, because the interface only consumes T. List<T> is invariant because it does both — which is why a List<Dog> is not a List<Animal>.

Go deeper: Covariance and Contravariance →
24. Select versus SelectMany?

Select maps each element to one result, so mapping each order to its lines gives a sequence of sequences. SelectMany maps each element to a sequence and flattens the results into one, giving you all the lines of all the orders in a single sequence. It is the LINQ equivalent of a nested loop.

Go deeper: Projection →

Async and concurrency

25. What does async/await actually do?

An await on an incomplete task returns control to the caller and registers the rest of the method as a continuation to run when the task completes; the thread is freed in the meantime. It is not "run this on another thread": awaiting a CPU-bound method still runs it on the current thread. Its purpose is to let I/O-bound work (network, disk, database) proceed without holding a thread, so a server can serve many requests with few threads.

Go deeper: Async and Await →
26. What is the difference between a Task and a Thread?

A Thread is an operating-system thread you own and schedule. A Task is a promise of a future result that may or may not involve a thread at all — an I/O task completes on a callback without any thread waiting. Task.Run queues CPU work to the thread pool. In modern .NET you almost never create threads directly.

Go deeper: Task and Task<T> →
27. Why is async void a problem?

An async void method cannot be awaited, so callers cannot know when it finishes, and an exception it throws has no task to land in — it is raised on the synchronisation context and usually crashes the process. Use async Task for everything except event handlers, which are the one place the signature forces void.

Go deeper: Common Async Mistakes →
28. How does calling .Result or .Wait() cause a deadlock?

In a context that runs continuations on a specific thread (a UI thread, classic ASP.NET), blocking that thread on .Result means the awaited task's continuation is queued to run on the same thread that is now blocked waiting for it. Neither can proceed. ASP.NET Core has no such context, so the deadlock does not occur there, but blocking still wastes a thread-pool thread and is how thread-pool starvation begins. The fix is to await all the way up.

Go deeper: Deadlocks →
29. What does ConfigureAwait(false) do?

It tells the awaiter not to capture the current synchronisation context, so the continuation may run on any thread-pool thread. In library code that never touches UI or request state, it avoids unnecessary context switches and one class of deadlock. In ASP.NET Core it is harmless but unnecessary; in UI code it is wrong if the continuation touches controls.

Go deeper: Synchronization Context →
30. How does cancellation work in .NET?

Cooperatively. A CancellationTokenSource owns a CancellationToken that is passed down the call chain; operations check IsCancellationRequested or call ThrowIfCancellationRequested(), and I/O APIs accept the token and abort when it fires. Nothing is forcibly killed. Every async method that can take a token should take one and pass it on.

Go deeper: CancellationToken →
31. When do you use lock, Interlocked, and the concurrent collections?

lock gives mutual exclusion around a block of code; use it when several statements must be atomic together. Interlocked performs single atomic operations (increment, exchange, compare-and-swap) without a lock, for counters and flags. ConcurrentDictionary and friends are thread-safe for individual operations, but a check-then-act sequence across two calls is still a race — use GetOrAdd and AddOrUpdate instead.

Go deeper: Locking and Synchronization →
32. What is ValueTask and when should you use it?

A struct that can hold either a result or a task, so a method that often completes synchronously (a cache hit, say) can return without allocating a Task. Use it on hot paths that usually complete synchronously; keep Task everywhere else, because ValueTask may be awaited only once and must not be stored or awaited concurrently.

Go deeper: ValueTask →
33. What is thread-pool starvation?

The condition where every pool thread is blocked (usually on .Result, .Wait(), or a synchronous call inside async code) and new work — including the continuations that would unblock them — cannot run. Requests queue, latency spikes, and the pool injects threads slowly. The signature is a server that grinds to a halt under load with low CPU. The cure is to remove the blocking.

Go deeper: Thread Pool Starvation →

Memory and the runtime

34. How does the .NET garbage collector work?

It is a generational, tracing collector. New objects are allocated in generation 0, which is small and collected often; survivors are promoted to generation 1 and then 2, which is collected rarely. A collection finds everything reachable from roots (stacks, statics, handles), frees the rest, and compacts. Objects over 85 KB go to the large object heap, which is collected with generation 2. The design assumption — most objects die young — is what makes allocation cheap.

Go deeper: Generational GC →
35. What is IDisposable, and what does using do?

IDisposable is the contract for releasing unmanaged or scarce resources (file handles, sockets, database connections) deterministically, rather than whenever the GC gets around to it. using guarantees Dispose() is called when the scope ends, even if an exception is thrown. Finalizers are a safety net for the unmanaged case only and should not be relied on for timing.

Go deeper: Memory Allocation →
36. Are value types always on the stack?

No, and this is a favourite trick question. A local struct lives on the stack; a struct that is a field of a class lives inside that object on the heap; a struct in an array lives in the array's heap memory; a boxed struct is on the heap; and a captured struct in a closure is on the heap. Storage location is about where the containing thing lives, not about the type.

Go deeper: Stack vs Heap →
37. What is Span<T>?

A ref struct that provides a type-safe, bounds-checked view over a contiguous region of memory — an array, a slice of one, stack memory, or unmanaged memory — without copying. It lets you parse, slice and process data with zero allocations. Because it is a ref struct, it can live only on the stack: it cannot be a class field, boxed, or captured by a lambda or async method.

Go deeper: Span<T> →
38. What does the JIT do, and what is tiered compilation?

C# compiles to Intermediate Language; the Just-In-Time compiler turns each method into native code the first time it runs, for the exact CPU it is on. Tiered compilation first emits quick, lightly optimised code (tier 0), then recompiles hot methods with full optimisation (tier 1) — and, with dynamic PGO, using profile data gathered at runtime. This is why .NET applications get faster in the first minute after start-up.

Go deeper: JIT Compilation →
39. How would you find a memory leak in a .NET service?

Confirm it first: watch working set and GC heap size over time under steady load. Then capture a dump (dotnet-gcdump or dotnet-dump) and look at what is growing and what is holding it. The usual culprits are event handlers that were never unsubscribed, static caches without eviction, captured closures in long-lived objects, and HttpClient misuse. Managed "leaks" are always a reachable reference somebody forgot about.

Go deeper: Memory Leaks →

ASP.NET Core

40. Explain the middleware pipeline.

Every request passes through an ordered chain of middleware components; each can act on the request, call the next one, and then act on the response on the way back out. Order matters: exception handling goes first so it wraps everything, then HTTPS redirection, static files, routing, authentication, authorization, and finally the endpoint. A component that does not call next short-circuits the pipeline — that is how static files and auth challenges work.

Go deeper: Middleware →
41. What are the DI lifetimes, and what is a captive dependency?

Transient: a new instance every time it is requested. Scoped: one instance per request (per scope). Singleton: one instance for the lifetime of the application. A captive dependency is a longer-lived service holding a shorter-lived one — classically a singleton that takes a scoped DbContext in its constructor. The context is then shared across all requests forever, which is a data-corruption and threading bug. The container validates this in development; in production it is the most common DI mistake in .NET.

Go deeper: Service Lifetimes →
42. Minimal APIs or controllers?

Both are first-class. Minimal APIs are lambdas mapped to routes with less ceremony and slightly better throughput, and suit small services and microservices. Controllers group related actions, support filters and conventions, and suit larger APIs with cross-cutting behaviour. They can coexist in one app; the choice is about organisation, not capability.

Go deeper: Minimal APIs →
43. Authentication versus authorization?

Authentication establishes who the caller is, producing a ClaimsPrincipal from a cookie, a bearer token or a certificate. Authorization decides what that principal may do — via roles, policies, or resource-based checks. In the pipeline, UseAuthentication must come before UseAuthorization, and both after routing.

Go deeper: Authorization →
44. How does JWT authentication work?

A JSON Web Token is a signed set of claims. The issuer signs it with a private key (or shared secret); the API validates the signature, issuer, audience and expiry on every request without a database call, then builds the principal from the claims. Because the token cannot be revoked once issued, keep lifetimes short and pair with refresh tokens. Never put secrets in the payload — it is only encoded, not encrypted.

Go deeper: JWT →
45. How do model binding and validation work?

Model binding maps route values, query strings, headers and the request body onto parameters and objects, using inference or explicit [FromBody], [FromQuery] and friends. Validation then runs data annotations (or a library such as FluentValidation) and, in controllers with [ApiController], automatically returns a 400 with a problem-details body when it fails. Minimal APIs validate via filters or explicit calls.

Go deeper: Validation →
46. What options do you have for caching in ASP.NET Core?

In-process IMemoryCache for a single instance; IDistributedCache (Redis, SQL) shared across instances; output caching for whole responses; and HybridCache, which layers a local cache in front of a distributed one and protects against cache stampedes. The design questions are always the same: what is the key, how long is it valid, and how is it invalidated when the underlying data changes.

Go deeper: Caching →

Entity Framework Core and data

47. What should the lifetime of a DbContext be?

Scoped — one per request, which is what AddDbContext registers. A DbContext is not thread-safe and tracks every entity it loads, so a long-lived one grows without bound and breaks under concurrent use. For background services and pooled scenarios, use IDbContextFactory<T> to create short-lived contexts on demand.

Go deeper: DbContext →
48. What does AsNoTracking do, and when should you use it?

By default EF Core keeps a snapshot of every entity it loads so it can detect changes for SaveChanges. AsNoTracking() skips that, making read-only queries faster and lighter. Use it for any query whose results you will not modify — which in most applications is the majority of queries.

Go deeper: Tracking vs No-Tracking →
49. What is the N+1 problem?

Loading a list of parents with one query, then triggering one more query per parent to load its children — a hundred orders becoming a hundred and one round trips. It hides behind lazy loading and innocent-looking loops. Fix it with Include to eager-load, with a projection that selects exactly the shape you need, or with split queries for wide graphs.

Go deeper: Query Optimization →
50. How do you handle concurrent updates to the same row?

Optimistic concurrency: mark a column as a concurrency token (a row version), and EF Core includes its original value in the UPDATE's WHERE clause. If another writer changed the row first, zero rows are affected and EF throws DbUpdateConcurrencyException, which you handle by reloading, merging or telling the user. Pessimistic locking is rarer and needs explicit transactions and database-specific hints.

Go deeper: Concurrency →
51. When is the repository pattern worth it over using DbContext directly?

DbContext already is a repository and unit of work, so wrapping it in generic IRepository<T> interfaces usually adds indirection without value. A repository earns its place when it hides genuinely complex query logic behind a domain-named method, when you have multiple data sources, or when the domain layer must not reference EF at all. Be able to argue both sides.

Go deeper: Repository Pattern — When and Why →

Architecture and distributed systems

52. What is clean architecture, in practice?

Dependencies point inward: the domain (entities, rules) knows nothing about the application layer, which knows nothing about infrastructure (database, HTTP, messaging) or the presentation layer. Interfaces are defined by the inner layers and implemented by the outer ones. The payoff is that business rules can be tested without a database and infrastructure can change without touching the domain. The cost is more projects and more mapping; for a small service, a single well-organised project is a legitimate answer.

Go deeper: Clean Architecture →
53. What is idempotency, and why does it matter for APIs and messaging?

An operation is idempotent if doing it twice has the same effect as doing it once. Networks retry, queues redeliver, and users double-click, so "charge the card" must be safe to receive twice. The usual mechanism is an idempotency key supplied by the caller and recorded with the result, so a repeat returns the stored outcome instead of acting again.

Go deeper: Idempotency →
54. Explain the outbox pattern.

When a service must update its database and publish a message, doing them as two separate steps can leave one done and the other not. The outbox pattern writes the message into an outbox table in the same database transaction as the business change, and a separate process reads the outbox and publishes. Either both happen or neither does, with at-least-once delivery to the broker — which is why consumers must be idempotent.

Go deeper: Outbox Pattern →
55. What is a circuit breaker, and how is it different from a retry?

A retry repeats a failed call, which is right for transient blips but harmful when the downstream is genuinely down — it adds load to something already failing. A circuit breaker counts failures and, past a threshold, "opens": calls fail immediately for a cooling-off period, then a trial call tests whether to close it again. In .NET both are provided by the resilience pipelines in Microsoft.Extensions.Resilience (built on Polly).

Go deeper: Circuit Breakers →
56. When would you use a message queue instead of an HTTP call?

When the caller does not need the answer now, when the work should survive the receiver being down, when you need to smooth spikes, or when several consumers should react to one event. HTTP is right for request-response where the caller needs the result to proceed. The trade is latency and simplicity for decoupling and resilience — and with a queue you take on ordering, duplicates and eventual consistency.

Go deeper: Message-Based Architecture →

Testing

57. Unit test or integration test?

A unit test exercises one piece of logic in isolation, fast and deterministic, with dependencies replaced by doubles. An integration test exercises real collaboration — your API against a real database in a container, for example — and catches the bugs that live at the seams: mappings, SQL, serialisation, configuration. Healthy .NET projects have many of the first and a meaningful number of the second; WebApplicationFactory and Testcontainers make the second practical.

Go deeper: Integration Testing →
58. What should you mock, and what should you not?

Mock the boundaries you do not own or cannot run cheaply: external HTTP services, clocks, message brokers, payment gateways. Do not mock the code under test's own collaborators just to make assertions about calls, and do not mock DbContext — use an in-memory provider for pure logic or a real database for anything involving queries. Over-mocking produces tests that pass while the system is broken.

Go deeper: Mocking →

Production debugging

59. A service is at 100% CPU. How do you find out why?

Capture a trace with dotnet-trace or dotnet-counters first to see whether it is your code, the GC, or the thread pool. High GC time points at allocation churn; a hot method points at an algorithm or a regex or a serialiser in a loop; many threads spinning points at a lock or a busy-wait. Then reproduce under a profiler and fix the top of the flame graph, not the thing you guessed.

Go deeper: High CPU →
60. How do you approach a production incident?

Stabilise first (roll back, scale, fail over), then diagnose with the telemetry you have — logs, metrics, traces, health checks — then fix forward, then write it up blamelessly so the same class of failure gets prevented, not just this instance. Interviewers asking this want to hear that you prioritise recovery over root cause in the moment, and root cause over blame afterwards.

Go deeper: Production Incident Analysis →

A one-week revision plan

If the interview is a week away, this order covers the highest-frequency topics first and leaves the last day for the coding exercise:

  1. Day 1: Value vs reference types, boxing, equality and hashing, records.
  2. Day 2: async/await, common async mistakes, deadlocks, thread-pool starvation.
  3. Day 3: GC, stack vs heap, Span<T>, memory leaks.
  4. Day 4: deferred execution, IEnumerable vs IQueryable, variance, dictionary internals.
  5. Day 5: middleware, DI lifetimes, auth, EF tracking, N+1.
  6. Day 6: SOLID, clean architecture, idempotency, outbox, circuit breakers.
  7. Day 7: Practise the coding exercise: solve two problems from scratch in a console app, out loud, with tests. The Intermediate C# Challenge is a good rehearsal.

Questions worth asking them

An interview runs both ways. Questions that tell you a lot about a .NET team: Which .NET version are you on, and what is the upgrade cadence? How do you run tests in CI, and how long does the pipeline take? What does on-call look like, and what was the last incident? How much of the codebase is covered by nullable reference types? The answers say more about your next two years than the job description does.

Want the full picture rather than the interview version? Everything here is a summary of a lesson in the course, and the Start Here guide has a path for interview preparation.