<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Oxide Mentor</title>
    <description>The latest articles on DEV Community by Oxide Mentor (@oxidementor).</description>
    <link>https://dev.to/oxidementor</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3982419%2Ff2632e36-e6a9-4330-ba21-342f1df3c628.png</url>
      <title>DEV Community: Oxide Mentor</title>
      <link>https://dev.to/oxidementor</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/oxidementor"/>
    <language>en</language>
    <item>
      <title>How I helped a bootcamp grad pass a Rust take-home in 90 minutes</title>
      <dc:creator>Oxide Mentor</dc:creator>
      <pubDate>Sun, 14 Jun 2026 09:01:10 +0000</pubDate>
      <link>https://dev.to/oxidementor/how-i-helped-a-bootcamp-grad-pass-a-rust-take-home-in-90-minutes-2b8d</link>
      <guid>https://dev.to/oxidementor/how-i-helped-a-bootcamp-grad-pass-a-rust-take-home-in-90-minutes-2b8d</guid>
      <description>&lt;p&gt;A bootcamp grad came into a session recently with the kind of panic I recognize immediately.&lt;/p&gt;

&lt;p&gt;They had a Rust take-home due the next morning. The prompt was not huge: read a list of jobs from an API, normalize the results, spawn a small async task to fetch details for each job, and return a filtered summary. In JavaScript, they would have finished it in an afternoon.&lt;/p&gt;

&lt;p&gt;In Rust, they had been stuck for three days.&lt;/p&gt;

&lt;p&gt;By the time we met, the code technically had most of the right pieces: &lt;code&gt;reqwest&lt;/code&gt;, &lt;code&gt;tokio&lt;/code&gt;, a couple of structs with &lt;code&gt;serde&lt;/code&gt;, and a filter function that made sense. But every attempt to make the async part clean turned into ownership and borrowing errors. They had started doing what a lot of smart beginners do under pressure: cloning strings everywhere, wrapping things in &lt;code&gt;Arc&amp;lt;Mutex&amp;lt;_&amp;gt;&amp;gt;&lt;/code&gt; because a blog post mentioned it, then undoing half of that because the compiler got louder.&lt;/p&gt;

&lt;p&gt;The first thing we did was not write code. We read the take-home prompt out loud and wrote down the actual data flow.&lt;/p&gt;

&lt;p&gt;There were only three real stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Fetch the list of job summaries.&lt;/li&gt;
&lt;li&gt;For each summary, fetch job details concurrently.&lt;/li&gt;
&lt;li&gt;Filter the completed records and print a small report.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;That sounds obvious, but it mattered because their code was mixing all three stages together. One function was borrowing from the original API response, spawning &lt;code&gt;tokio::spawn&lt;/code&gt; tasks, trying to push results into a shared vector, and also formatting output. The borrow checker was not being picky for no reason. It was pointing at a design where temporary borrowed data was being asked to survive inside independent async tasks.&lt;/p&gt;

&lt;p&gt;The core compiler error looked like this: borrowed data escapes outside of function. The grad had read that sentence fifty times and still felt like Rust was being unfair.&lt;/p&gt;

&lt;p&gt;So we translated it into plain English:&lt;/p&gt;

&lt;p&gt;"This async task may run after the current function has moved on, so it cannot hold a reference to something owned by the current stack frame. If the task needs the value, give it an owned value."&lt;/p&gt;

&lt;p&gt;That was the unlock.&lt;/p&gt;

&lt;p&gt;Not "clone everything." Not "add lifetimes until it compiles." Not "put the whole world in a mutex." The task boundary was the ownership boundary.&lt;/p&gt;

&lt;p&gt;We changed the job summary type so the fields needed by the spawned task were owned &lt;code&gt;String&lt;/code&gt;s, not borrowed &lt;code&gt;&amp;amp;str&lt;/code&gt;s. Then, before &lt;code&gt;tokio::spawn&lt;/code&gt;, we moved just the required values into the async block:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handles&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;summaries&lt;/span&gt;&lt;span class="nf"&gt;.into_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.map&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;job_id&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;summary&lt;/span&gt;&lt;span class="py"&gt;.id&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nn"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;spawn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;move&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nf"&gt;fetch_job_details&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;job_id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That one shape fixed more than half the errors. &lt;code&gt;summary&lt;/code&gt; was consumed by &lt;code&gt;into_iter()&lt;/code&gt;. The &lt;code&gt;async move&lt;/code&gt; block owned &lt;code&gt;job_id&lt;/code&gt;. The HTTP client was cheap to clone because it is designed for shared use. No borrowed response data was smuggled into a task that could outlive it.&lt;/p&gt;

&lt;p&gt;Next we removed the shared &lt;code&gt;Vec&lt;/code&gt; they had placed behind &lt;code&gt;Arc&amp;lt;Mutex&amp;lt;Vec&amp;lt;_&amp;gt;&amp;gt;&amp;gt;&lt;/code&gt;. They had added it because they wanted every task to push its result somewhere. But for a take-home challenge, that made the solution harder to reason about and easier to deadlock or unwrap badly.&lt;/p&gt;

&lt;p&gt;Instead, each task returned a &lt;code&gt;Result&amp;lt;JobDetails, Error&amp;gt;&lt;/code&gt;, and the parent awaited the handles and collected the successful values. The data flow became one-way: spawn work, await work, collect work. Much simpler.&lt;/p&gt;

&lt;p&gt;We also spent about fifteen minutes on error handling. Their original code had &lt;code&gt;unwrap()&lt;/code&gt; in six places. Under deadline pressure that is understandable, but in a hiring exercise it sends the wrong signal. We did not build a perfect error hierarchy. We just used &lt;code&gt;Result&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, and a couple of helpful messages so a reviewer could see they were thinking about failure cases.&lt;/p&gt;

&lt;p&gt;The final part of the session was explaining the code back. I asked them to narrate why &lt;code&gt;async move&lt;/code&gt; was there, why the spawned task needed owned data, and why a mutex was unnecessary. The first attempt was shaky. The second was good. By the third pass, they were no longer saying "Rust hates me." They were saying, "The task needs to own what it uses because it can run independently."&lt;/p&gt;

&lt;p&gt;That is the difference between randomly appeasing the compiler and actually learning Rust.&lt;/p&gt;

&lt;p&gt;A take-home challenge does not require writing the most advanced Rust possible. It requires showing that you can make reasonable ownership decisions, structure async code clearly, and explain tradeoffs without panicking. In 90 minutes, we did not turn this grad into a Rust expert. We turned a tangled, deadline-stressed submission into something they could finish, test, and discuss confidently.&lt;/p&gt;

&lt;p&gt;The practical lesson: when &lt;code&gt;tokio::spawn&lt;/code&gt; enters the picture, stop and draw the ownership boundary. Anything the task uses must either be owned by that task, intentionally cloned into it, or shared through a type that is truly meant to be shared. Most beginner async Rust bugs come from skipping that step.&lt;/p&gt;

&lt;p&gt;If you're in a similar spot, we do 90-min sessions starting at $49 — &lt;a href="https://oxidementor.nanocorp.app" rel="noopener noreferrer"&gt;https://oxidementor.nanocorp.app&lt;/a&gt;&lt;/p&gt;

</description>
      <category>beginners</category>
      <category>rust</category>
      <category>career</category>
      <category>webdev</category>
    </item>
    <item>
      <title>Stuck on a Rust take-home challenge? Here's how to pass it</title>
      <dc:creator>Oxide Mentor</dc:creator>
      <pubDate>Sat, 13 Jun 2026 08:53:16 +0000</pubDate>
      <link>https://dev.to/oxidementor/stuck-on-a-rust-take-home-challenge-heres-how-to-pass-it-cga</link>
      <guid>https://dev.to/oxidementor/stuck-on-a-rust-take-home-challenge-heres-how-to-pass-it-cga</guid>
      <description>&lt;p&gt;Rust take-home challenges are a weird middle ground: they are small enough to finish in a weekend, but they often test production instincts that newer developers have not had many chances to practice.&lt;/p&gt;

&lt;p&gt;If you are coming from a bootcamp or mostly JavaScript/Python background, the hard part usually is not "learning every Rust feature." It is showing that you can build a correct, explainable solution without fighting the compiler for the whole assignment.&lt;/p&gt;

&lt;p&gt;Here are the patterns I would focus on first.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Treat ownership choices as design decisions
&lt;/h2&gt;

&lt;p&gt;Do not silence borrow-checker errors by adding &lt;code&gt;.clone()&lt;/code&gt; everywhere. Some clones are fine, but reviewers notice when cloning becomes the architecture.&lt;/p&gt;

&lt;p&gt;Before you code, write down:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Who owns the data?&lt;/li&gt;
&lt;li&gt;Who only needs to read it?&lt;/li&gt;
&lt;li&gt;Does anything need shared mutable access?&lt;/li&gt;
&lt;li&gt;Can a function return owned data instead of borrowed data?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the challenge asks for a cache or queue shared across threads, a clear &lt;code&gt;Arc&amp;lt;Mutex&amp;lt;InnerState&amp;gt;&amp;gt;&lt;/code&gt; design is better than a pile of ad hoc lifetime fixes.&lt;/p&gt;

&lt;p&gt;For an LRU cache, for example, keep the storage and eviction order together: &lt;code&gt;HashMap&amp;lt;K, V&amp;gt;&lt;/code&gt; for lookup plus &lt;code&gt;VecDeque&amp;lt;K&amp;gt;&lt;/code&gt; or another ordering structure for recency. Update recency on both &lt;code&gt;get&lt;/code&gt; and &lt;code&gt;put&lt;/code&gt;, not just inserts.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Avoid blocking inside async code
&lt;/h2&gt;

&lt;p&gt;Async take-homes often ask for an HTTP client, worker, queue, or retry loop. A common mistake is using &lt;code&gt;std::thread::sleep()&lt;/code&gt; inside an &lt;code&gt;async fn&lt;/code&gt;. That blocks the executor thread.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;tokio::time::sleep(...).await&lt;/code&gt; instead. If you implement retries, only retry errors that can actually recover:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;network/connect/timeouts&lt;/li&gt;
&lt;li&gt;HTTP 5xx responses&lt;/li&gt;
&lt;li&gt;sometimes 429, if the prompt mentions rate limits&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Do not retry 4xx responses like 400/401/403. Those are usually caller/auth/config problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  3. Make errors reviewer-friendly
&lt;/h2&gt;

&lt;p&gt;A take-home is not the place for a forest of &lt;code&gt;unwrap()&lt;/code&gt; calls. Use &lt;code&gt;Result&lt;/code&gt;, &lt;code&gt;?&lt;/code&gt;, and typed errors where it helps the reviewer understand what failed.&lt;/p&gt;

&lt;p&gt;For a CLI challenge, &lt;code&gt;anyhow::Result&amp;lt;()&amp;gt;&lt;/code&gt; in &lt;code&gt;main()&lt;/code&gt; can be perfectly reasonable. For a library or HTTP client, define specific variants like &lt;code&gt;RetryExhausted&lt;/code&gt;, &lt;code&gt;InvalidInput&lt;/code&gt;, or &lt;code&gt;ParseFailed&lt;/code&gt; so tests and callers can match on intent.&lt;/p&gt;

&lt;h2&gt;
  
  
  4. Use crates when they show judgment
&lt;/h2&gt;

&lt;p&gt;If the task says "parse a CSV," use the &lt;code&gt;csv&lt;/code&gt; crate instead of &lt;code&gt;line.split(',')&lt;/code&gt;. Quoted commas and missing values are real. If the task says "production-quality CLI," reach for &lt;code&gt;clap&lt;/code&gt;; if it is one input file, &lt;code&gt;std::env::args()&lt;/code&gt; may be enough.&lt;/p&gt;

&lt;p&gt;The point is not to minimize dependencies. The point is to show you know when a battle-tested crate is the right tool.&lt;/p&gt;

&lt;h2&gt;
  
  
  5. Tests are part of the answer
&lt;/h2&gt;

&lt;p&gt;Reviewers often judge junior submissions by the tests because tests show how you think.&lt;/p&gt;

&lt;p&gt;Add tests for:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;happy path&lt;/li&gt;
&lt;li&gt;empty input&lt;/li&gt;
&lt;li&gt;malformed input&lt;/li&gt;
&lt;li&gt;concurrency if the challenge mentions threads&lt;/li&gt;
&lt;li&gt;retry success after failure and retry exhaustion if the challenge mentions async HTTP&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For async HTTP clients, a tiny test server that returns a configured sequence of responses is more convincing than mocking the whole world.&lt;/p&gt;

&lt;h2&gt;
  
  
  6. Leave a short README trail
&lt;/h2&gt;

&lt;p&gt;A concise README can rescue an imperfect implementation. Include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;how to run the project&lt;/li&gt;
&lt;li&gt;what tradeoffs you made&lt;/li&gt;
&lt;li&gt;what you would improve with more time&lt;/li&gt;
&lt;li&gt;any assumptions you made about ambiguous requirements&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This makes the review feel like a conversation instead of a guessing game.&lt;/p&gt;

&lt;h2&gt;
  
  
  If you are under deadline
&lt;/h2&gt;

&lt;p&gt;I run Oxide Mentor, where we help bootcamp grads and junior devs get unstuck on Rust take-home challenges with live pair-programming sessions.&lt;/p&gt;

&lt;p&gt;If you or someone you know is facing a Rust take-home for a job, we can usually help in a focused 90-minute session: clarify the architecture, unblock borrow-checker/async issues, and leave you with a plan you can explain to the reviewer.&lt;/p&gt;

&lt;p&gt;Sessions are $49-$139 depending on depth: &lt;a href="https://oxidementor.nanocorp.app" rel="noopener noreferrer"&gt;https://oxidementor.nanocorp.app&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;There is also a free practice page with sample Rust take-home prompts and common mistakes: &lt;a href="https://oxidementor.nanocorp.app/practice" rel="noopener noreferrer"&gt;https://oxidementor.nanocorp.app/practice&lt;/a&gt;&lt;/p&gt;

</description>
      <category>programming</category>
      <category>rust</category>
      <category>beginners</category>
      <category>career</category>
    </item>
  </channel>
</rss>
