4 ms·
I heard about this project from a friend who works at KA. I am concerned about the strategy, and I think the following approach would yield better results: 1.
by d_burfoot 7y ago
I heard about this project from a friend who works at KA. I am concerned about the strategy, and I think the following approach would yield better results:
1. Write in Go an exact reimplementation of the current Python codebase. Use the same database schema, front-end HTML/JS, test suite, and so on. To whatever extent possible, use the same names for classes and functions. Check the reimplementation correctness by using a comparison tool that calls both the Python and Go version of a page/function/search and making sure that they produce the same results.
2. Change the production code over to the Go version, perhaps using a ramping strategy where X% of servers are running the Go code, and you gradually increase X, while monitoring vital statistics like server load and response time.
3. Now that the production site is running Go, incrementally split off components into their own services.
This approach leads you to the same destination, but with a lot less risk. It is very unhealthy to have a situation where the production site is running one codebase but all the developers are working on another codebase. Note that you will realize the benefits of Go (performance, type safety) after step 2, which is much sooner than OP's plan.
Joel Spolsky's classic essay about how you should never do full codebase rewrites is worth reviewing:
https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/ https://www.joelonsoftware.com/2000/04/06/things-you-should-...
- jordanbeiber 7y agoIs moving directly to #3 not an option? I’m thinking that defining parts that can be moved to separate services, and start consuming these could be a way to organically transition to a new architecture.
- krenel 7y ago100% agree. We've just finished to roll out our implementation in Go migrating a subsystem from PHP and receiving around 150req/second and demultiplexing those request to 1500-2000req/second to legacy backends. The key to the success of the project was that the API was an exact match, and we could compare both implementations for exact requests. The deploy strategy of the new version: - Reply the real traffic to the new Go service comparing the results with the old one - Then implement a toggle feature than enabled different traffic sources to use one backend or the other - Keep changing backends to the new system and ensure that metrics were unaffected Having e2e and integration tests for the Golang project was of a huge help, since we could fix all differences using TDD. Although we changed some of the implementations to take advantage of Go constructs, just a 1-to-1 replacement would have had a huge performance impact.
- KhalPanda 7y agoSounds nice in theory, but won't you always be playing catch-up? Or will development(/bugfixes) halt on the existing python version? Would it ever be acceptable to the business to commence such a rewrite without any show of value until after completion? (Speaking as someone working at a firm that did choose (before my time) to start a ground-up rewrite than ran about 3 years over estimate).
- sethammons 7y agoHaving done this kind of migration/rewrite multiple times, the way you succeed is starting with acceptance tests that verify functionality from the API layer that is implementation agnostic. After the tests are in place, you break off small portions into microservises and ensure tests pass. You pass a small percentage of traffic through the new arch, fixing bugs and leveraging telemetry. You eventually slide all traffic to the new architecture. You want to get something receiving traffic asap as to start getting feedback. Often this means taking something smaller or simpler out of the lagacy codebase first. Doing a complete, side by side replica is a recipe for disaster. Think MVP. We've even introduced traffic routing based on feature sets so you can route users who don't use edge case features the new arch which has yet to incorporate the those features while keeping others on the old arch.
- dangoor 7y agoIt looks like I need to write a followup with more details about how our migration looks! Since we're using GraphQL federation, we have a gateway which serves up our complete GraphQL schema, pulled together from a collection of services behind the gateway. We can move individual properties over from our Python monolith to new Go services and the clients will never know. Plus, we can do side-by-side testing in the gateway by making a request to the monolith and to the new service and comparing the results (something we don't have yet, but plan to). This is definitely not a big bang rewrite. It's about as incremental as it can be, because we can move individual GraphQL properties over and the gateway stitches the result together.