FREE DEVELOPER TRANSMISSION
Developer Learning Lab
Small, runnable lessons inspired by DrakimaCore’s engineering principles. Learn the idea in a console-sized example, try an exercise, then explain the tradeoff in your own words.
Build a replaceable message provider
Learn dependency inversion with a tiny console application whose use case owns the interface and whose provider is replaceable.
Concept
A boundary is valuable when the policy can be tested without the external system. This is the same architectural idea DrakimaCore uses for AI, storage, and media providers—reduced to a console-sized exercise.
public interface IMessageProvider
{
Task<string> GetMessageAsync(CancellationToken cancellationToken);
}
public sealed class WelcomeUseCase(IMessageProvider provider)
{
public async Task RunAsync(CancellationToken cancellationToken)
{
var message = await provider.GetMessageAsync(cancellationToken);
Console.WriteLine(message);
}
}
Build challenge
Create a second provider that reads a local JSON file, then test WelcomeUseCase with an in-memory fake.
Explain it back
- Which layer should own IMessageProvider?
- What changes when the provider becomes an HTTP client?
- What behavior can the use case test without I/O?
Cancel work without reporting a false failure
Practice propagating CancellationToken and separating expected user cancellation from an actual processing fault.
Concept
Reliable asynchronous code treats cancellation as a cooperative outcome. Every awaited boundary receives the token, while exception handling distinguishes a requested stop from a timeout or provider defect.
using var stop = new CancellationTokenSource(TimeSpan.FromSeconds(3));
try
{
await ProcessItemsAsync(stop.Token);
Console.WriteLine("Completed.");
}
catch (OperationCanceledException) when (stop.IsCancellationRequested)
{
Console.WriteLine("Stopped cleanly.");
}
Build challenge
Implement ProcessItemsAsync with Task.Delay and cancellation, then add a separate simulated exception and prove it is not mislabeled as cancellation.
Explain it back
- Where should the token originate?
- Why is catch (Exception) dangerous here?
- How would an HTTP request cancellation differ from a service timeout?
Move toward a target with vectors
Use subtraction, normalization, scalar multiplication, and distance to create frame-rate-independent 2D movement.
Concept
A vector encodes direction and magnitude. Subtracting positions yields the displacement; normalization preserves direction while removing distance; multiplying by speed and delta time produces a stable step.
var displacement = target - position;
if (displacement.Length() > 0.001f)
{
var direction = Vector2.Normalize(displacement);
position += direction * speed * deltaTime;
}
Build challenge
Prevent overshooting by clamping the step to the remaining distance, then print positions for both 30 FPS and 120 FPS simulations.
Explain it back
- Why normalize displacement?
- What does deltaTime protect against?
- How do dot products help with facing or field-of-view checks?
Animate an orbit and aim angle
Use sine, cosine, radians, and Atan2 to place an object on a circular path and orient it toward a target.
Concept
Sine and cosine convert an angle into vertical and horizontal components on a unit circle. Atan2 performs the inverse job while preserving the correct quadrant.
var angle = elapsedSeconds * angularSpeed;
var orbit = new Vector2(
MathF.Cos(angle) * radius,
MathF.Sin(angle) * radius);
var position = center + orbit;
var aimRadians = MathF.Atan2(target.Y - position.Y, target.X - position.X);
Build challenge
Write a console loop that prints eight positions around a circle, then convert the aim angle from radians to degrees for display.
Explain it back
- Why do APIs usually use radians?
- What goes wrong with atan(y / x)?
- How can phase offsets distribute objects evenly around a circle?