Ask HN: Have you ever migrated a large/old project to a different language?
I&#x27;ve done a few (started my career doing VB6 -&gt; .NET porting). Working Effectively with Legacy Code was the first book I read. Email&#x27;s in my profile<p>Team just &#x27;finished&#x27; a migration of a 10 year old codebase from Java -&gt; Kotlin (ended up with 100k SLOC). Part-time this took around 1.5 years, which was faster than I expected. Seeing benefits already but it&#x27;ll take years to see if it was worth the opportunity cost. Also in the middle of a second migration of some aspects of the codebase to Rust&#x2F;Svelte. Massive and permanent immediate benefits when this goes through.<p>- Have well-defined rationale, scope, and buy-in.<p>- Determine how you&#x27;ll approach bad code that nobody&#x27;s touched for a long time<p>- Testing guideline: ensure you &#x27;could&#x27; test the code in the &#x27;before&#x27; (typically about 15% coverage). If you can&#x27;t test the &#x27;after&#x27;, you&#x27;ve probably picked the wrong language<p>- CI is table-stakes.<p>- Define the level of interop between old and new code that you want.<p>- If you can avoid a &#x27;big bang&#x27;, do so. The burden of a &#x27;big test&#x27; beforehand and &#x27;everything is now unstable&#x27; afterwards isn&#x27;t an easy situation to solve (still working on this). Nobody wants to be in the position of &#x27;you did nothing and everything&#x27;s worse&#x27;<p>- Ensure you keep git blame working between old and new. git bisect is an ideal<p>- Set up linting immediately for the new project<p>- Optional: I went down the route of adding AST-based linting for a couple common errors&#x2F;issues. Tempted to add some more. Didn&#x27;t get a massive return from this but on balance it was worthwhile, this may be different for other projects.<p>- Convert and refactor separately (use your judgment on small refactors). When converting, add language-based annotations or standardised comments to areas which need love (tests, important for refactoring, or bad style). You don&#x27;t want to be in a situation where you&#x27;ve both introduced bugs from the conversion, then introduced bugs from a refactoring in the same commit. Only add &#x27;issue tracker tasks&#x27; for major opportunities or structural fixes.<p>- With the above annotations, you have a quantitative metric of &#x27;first we convert to 100%&#x27;, then &#x27;get the annotation count to 0&#x27;. It keeps focus, and gives microtasks to handle.<p>- Having &#x27;porting helper functions&#x27; is useful: you&#x27;re going to join strings 100 times, have a helper that works the same way and has similar syntax to the source language. You can use your IDE to inline that function to something more idiomatic when you&#x27;re done. Type aliases are awesome.<p>- Avoid lava layers[0]. After a conversion is &#x27;complete&#x27;, you should be consistent in your use of programming language(s). Aim to split the project if this isn&#x27;t the case. Also gives a compile time benefit to only use one toolchain<p>- Consider isolating toolchains within dependencies: I split out a Java -&gt; Rust interop library into a separate dependency: this massively helped onboard new developers as they only needed one download to get the &#x27;core&#x27; of the project running.<p>- You spent X years getting to a stable process with your current code, accept that it&#x27;ll take time and effort to get to the same level with your new language<p>- Automate the boring parts (depending on the size of your project): this can both be more fun, and save time with the conversion<p>[0] <a href="http:&#x2F;&#x2F;mikehadlow.blogspot.com&#x2F;2014&#x2F;12&#x2F;the-lava-layer-anti-pattern.html" rel="nofollow">http:&#x2F;&#x2F;mikehadlow.blogspot.com&#x2F;2014&#x2F;12&#x2F;the-lava-layer-anti-p...</a><p><pre><code>  When I was a King and a Mason -- a Master proven and skilled --
  I cleared me ground for a Palace such as a King should build.
  I decreed and dug down to my levels. Presently, under the silt,
  I came on the wreck of a Palace such as a King had built.
  
  There was no worth in the fashion -- there was no wit in the plan --
  Hither and thither, aimless, the ruined footings ran --
  Masonry, brute, mishandled, but carven on every stone:
  &quot;After me cometh a Builder. Tell him, I too have known.&quot;
  
  Swift to my use in my trenches, where my well-planned ground-works grew,
  I tumbled his quoins and his ashlars, and cut and reset them anew.
  Lime I milled of his marbles; burned it, slacked it, and spread;
  Taking and leaving at pleasure the gifts of the humble dead.
  
  Yet I despised not nor gloried; yet, as we wrenched them apart,
  I read in the razed foundations the heart of that builder&#x27;s heart.
  As he had risen and pleaded, so did I understand
  The form of the dream he had followed in the face of the thing he had planned.
  
              *   *   *   *   *
              
  When I was a King and a Mason -- in the open noon of my pride,
  They sent me a Word from the Darkness. They whispered and called me aside.
  They said -- &quot;The end is forbidden.&quot; They said -- &quot;Thy use is fulfilled.
  &quot;Thy Palace shall stand as that other&#x27;s -- the spoil of a King who shall build.&quot;
  
  I called my men from my trenches, my quarries, my wharves, and my sheers.
  All I had wrought I abandoned to the faith of the faithless years.
  Only I cut on the timber -- only I carved on the stone:
  &quot;After me cometh a Builder. Tell him, I too have known!&quot;</code></pre>