Skip to content

Separate translation and alignment into different assemblies - #1011

Merged
pmachapman merged 5 commits into
mainfrom
separate_translation_alignment
Jul 29, 2026
Merged

Separate translation and alignment into different assemblies#1011
pmachapman merged 5 commits into
mainfrom
separate_translation_alignment

Conversation

@pmachapman

@pmachapman pmachapman commented Jul 27, 2026

Copy link
Copy Markdown
Collaborator

Fixes #924.

There was some quite tight coupling in Serval.Machine.Shared with the build job runners, which I managed via abstraction rather than duplication, as I wanted to maintain a hierarchy where Serval.Machine.Translation and Serval.Machine.WordAlignment depend on Serval.Machine.Shared, rather than the other way around.

The downside of this approach is that LocalBuildJobRunner and ClearMLBuildJobRunner are each instantiated and run for TranslationEngine and WordAlignmentEngine. I think this should be OK, but if there is a requirement for just one global queue in LocalBuildJobRunner or ClearMLBuildJobRunner that I didn't pick up on, I will need a different approach.

I also took the opportunity to prune some unused code I noticed, clean up the project dependencies, and to migrate to the new SLNX format which I think is much nicer than the old SLN format (especially given I have added 4 new projects in this PR).


This change is Reviewable

@pmachapman
pmachapman requested review from Enkidu93 and ddaspit July 27, 2026 04:54

@ddaspit ddaspit left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ddaspit partially reviewed 18 files and all commit messages, and made 8 comments.
Reviewable status: 18 of 121 files reviewed, 8 unresolved discussions (waiting on Enkidu93 and pmachapman).


src/Machine/src/Serval.Machine.Shared/Configuration/IServalConfiguratorExtensions.cs line 19 at r1 (raw file):

        services.Configure<ServiceOptions>(configuration.GetSection(ServiceOptions.Key));
        services.Configure<SharedFileOptions>(configuration.GetSection(SharedFileOptions.Key));
        services.Configure<SmtTransferEngineOptions>(configuration.GetSection(SmtTransferEngineOptions.Key));

This should be moved to AddMachineTranslation.


src/Machine/src/Serval.Machine.Shared/Configuration/IServalConfiguratorExtensions.cs line 20 at r1 (raw file):

        services.Configure<SharedFileOptions>(configuration.GetSection(SharedFileOptions.Key));
        services.Configure<SmtTransferEngineOptions>(configuration.GetSection(SmtTransferEngineOptions.Key));
        services.Configure<StatisticalEngineOptions>(configuration.GetSection(StatisticalEngineOptions.Key));

This should be moved to AddMachineWordAlignment.


src/Machine/src/Serval.Machine.Shared/Configuration/IServalConfiguratorExtensions.cs line 81 at r1 (raw file):

    private static IServalConfigurator AddHealthChecks(this IServalConfigurator configurator)
    {
        var smtTransferEngineOptions = new SmtTransferEngineOptions();

The health checks should be moved to the appropriate assemblies.


src/Machine/src/Serval.Machine.Shared/Services/ClearMLMonitorService.cs line 31 at r1 (raw file):

    private readonly Dictionary<string, ProgressStatus> _curBuildStatus = new();

    private readonly IReadOnlyDictionary<EngineType, string> _queuePerEngineType =

The queues should be filtered according to the correct domain. I would suggest adding an extension method that converts the engine type to the correct engine group, i.e. x.EngineType.ToEngineGroup(). The extension method can be used wherever this conversion is needed. You will probably need to create new classes that inherit from this class to set the engine group.


src/Machine/src/Serval.Machine.Shared/Services/LocalBuildJobRunner.cs line 26 at r1 (raw file):

    };

    private readonly Dictionary<EngineGroup, Channel<string>> _jobChannels = new()

Do we still need both?


src/Machine/test/Serval.Machine.Translation.Tests/Services/ClearMLMonitorServiceTests.cs line 4 at r1 (raw file):

[TestFixture]
public class ClearMLMonitorServiceTests

This is very similar to the same test fixture in the word alignment assembly. Can they be shared in some way?


src/Machine/test/Serval.Machine.Translation.Tests/Services/PreprocessBuildJobTests.cs line 4 at r1 (raw file):

[TestFixture]
public class PreprocessBuildJobTests

This is very similar to the same test fixture in the word alignment assembly. Can they be shared in some way?


src/Machine/test/Serval.Machine.Translation.Tests/Services/SmtTransferEngineServiceTests.cs line 315 at r1 (raw file):

            services.AddScoped(_ => _deferredBuildJobService!);
            services.AddKeyedSingleton(EngineGroup.Translation, (_, _) => PlatformService);
            services.AddKeyedSingleton(EngineGroup.WordAlignment, (_, _) => Substitute.For<IPlatformService>());

I don't think this is needed.

@ddaspit

ddaspit commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

@pmachapman Now that you have a clear idea of how the code is structured with translation and word alignment separated, how do you feel about this change? Do you think it is worth doing? Do you think the separation would make the code more maintainable?

@pmachapman
pmachapman force-pushed the separate_translation_alignment branch from 90455ff to 48a0309 Compare July 28, 2026 00:42
@pmachapman
pmachapman requested a review from ddaspit July 28, 2026 00:47

@pmachapman pmachapman left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pmachapman Now that you have a clear idea of how the code is structured with translation and word alignment separated, how do you feel about this change?

@ddaspit I thought this change would be easier than it turned out to be. That said, it is done now, and as a part of it, some boundary issues have been cleaned up (which were what made this change harder than I thought).

The downside is the code is probably more inefficient because this are being twice, i.e. we no longer have just one ClearMLMonitorService running, but two. If we want the most efficient code route, we probably want to blur the boundaries more. I personally think the clearer boundaries are worth the trade off, as before I began I thought there were clearer boundaries between Translation Engine and Word Alignment Engine than I discovered.

Do you think it is worth doing?

Yes, as I think it will simplify the future removal of SMT, and it helps keep the boundary between Translation and Word Alignment Engines clearer. Whether that is a clear boundary we want to keep is an architectural question, and will ultimately decide the merit of this PR.

Do you think the separation would make the code more maintainable?

Yes, I think so, due to the clearer code boundaries.

@pmachapman made 9 comments.
Reviewable status: 16 of 127 files reviewed, 8 unresolved discussions (waiting on ddaspit and Enkidu93).


src/Machine/src/Serval.Machine.Shared/Configuration/IServalConfiguratorExtensions.cs line 19 at r1 (raw file):

Previously, ddaspit (Damien Daspit) wrote…

This should be moved to AddMachineTranslation.

Done.


src/Machine/src/Serval.Machine.Shared/Configuration/IServalConfiguratorExtensions.cs line 20 at r1 (raw file):

Previously, ddaspit (Damien Daspit) wrote…

This should be moved to AddMachineWordAlignment.

Done. I kept both of these here because of the check "SMT Engine and Statistical directory must be on the same drive", but looking at it now, that check is no longer required.


src/Machine/src/Serval.Machine.Shared/Configuration/IServalConfiguratorExtensions.cs line 81 at r1 (raw file):

Previously, ddaspit (Damien Daspit) wrote…

The health checks should be moved to the appropriate assemblies.

Done.


src/Machine/src/Serval.Machine.Shared/Services/ClearMLMonitorService.cs line 31 at r1 (raw file):

Previously, ddaspit (Damien Daspit) wrote…

The queues should be filtered according to the correct domain. I would suggest adding an extension method that converts the engine type to the correct engine group, i.e. x.EngineType.ToEngineGroup(). The extension method can be used wherever this conversion is needed. You will probably need to create new classes that inherit from this class to set the engine group.

Done. I followed a similar pattern to what I used for LocalBuildRunner.


src/Machine/src/Serval.Machine.Shared/Services/LocalBuildJobRunner.cs line 26 at r1 (raw file):

Previously, ddaspit (Damien Daspit) wrote…

Do we still need both?

No - I have scoped this to the engine group.

I think a lot of simplification could be done to the APIs for LocalBuildRunner


src/Machine/test/Serval.Machine.Translation.Tests/Services/ClearMLMonitorServiceTests.cs line 4 at r1 (raw file):

Previously, ddaspit (Damien Daspit) wrote…

This is very similar to the same test fixture in the word alignment assembly. Can they be shared in some way?

I have made the test a class generic, and moved it to IntegrationTests as that seemed to fit it better (and it had all of the dependencies). If that is a bit too abstract, let me know, and I will probably just make it TranslationEngine specific, and only perform a basic smoke test for the WordAlignmentEngine ClearMLMonitorService.


src/Machine/test/Serval.Machine.Translation.Tests/Services/PreprocessBuildJobTests.cs line 4 at r1 (raw file):

Previously, ddaspit (Damien Daspit) wrote…

This is very similar to the same test fixture in the word alignment assembly. Can they be shared in some way?

Done. I have de-duplicated these two test fixtures.


src/Machine/test/Serval.Machine.Translation.Tests/Services/SmtTransferEngineServiceTests.cs line 315 at r1 (raw file):

Previously, ddaspit (Damien Daspit) wrote…

I don't think this is needed.

Done. Removed here and elsewhere.

@codecov-commenter

codecov-commenter commented Jul 28, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 93.23308% with 18 lines in your changes missing coverage. Please review.
✅ Project coverage is 71.82%. Comparing base (8ddabc5) to head (9212914).

Files with missing lines Patch % Lines
...ion/Configuration/IServalConfiguratorExtensions.cs 95.87% 2 Missing and 2 partials ⚠️
...Translation/Services/TranslationBuildJobService.cs 20.00% 4 Missing ⚠️
...ent/Configuration/IServalConfiguratorExtensions.cs 95.06% 2 Missing and 2 partials ⚠️
...e/src/Serval.Machine.Shared/Services/EngineType.cs 66.66% 1 Missing and 1 partial ⚠️
.../Serval.Machine.Shared/Services/BuildJobService.cs 90.90% 1 Missing ⚠️
...rval.Machine.Shared/Services/PreprocessBuildJob.cs 50.00% 0 Missing and 1 partial ⚠️
...ation/Services/ServalTranslationPlatformService.cs 0.00% 1 Missing ⚠️
...ent/Services/ServalWordAlignmentPlatformService.cs 0.00% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #1011      +/-   ##
==========================================
+ Coverage   71.72%   71.82%   +0.09%     
==========================================
  Files         370      374       +4     
  Lines       20287    20278       -9     
  Branches     2686     2686              
==========================================
+ Hits        14551    14564      +13     
+ Misses       4670     4647      -23     
- Partials     1066     1067       +1     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@ddaspit ddaspit left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

@ddaspit partially reviewed 111 files and all commit messages, made 1 comment, and resolved 8 discussions.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on Enkidu93).

@Enkidu93 Enkidu93 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

@Enkidu93 partially reviewed 127 files and all commit messages, and made 2 comments.
Reviewable status: all files reviewed, 1 unresolved discussion (waiting on pmachapman).


src/Serval/test/Serval.ApiServer.IntegrationTests/StatusTests.cs line 26 at r2 (raw file):

        {
            case 200:
                // the grpc services are not running, so the health check will fail

Not your change, but I don't think this comment is in the right place or even relevant anymore

@pmachapman
pmachapman force-pushed the separate_translation_alignment branch from 48a0309 to 57a6398 Compare July 29, 2026 19:11
@pmachapman
pmachapman requested review from Enkidu93 and ddaspit July 29, 2026 19:11

@pmachapman pmachapman left a comment

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pmachapman made 1 comment and resolved 1 discussion.
Reviewable status: 126 of 127 files reviewed, all discussions resolved (waiting on ddaspit and Enkidu93).


src/Serval/test/Serval.ApiServer.IntegrationTests/StatusTests.cs line 26 at r2 (raw file):

Previously, Enkidu93 (Eli C. Lowry) wrote…

Not your change, but I don't think this comment is in the right place or even relevant anymore

Done - Removed.

@pmachapman
pmachapman force-pushed the separate_translation_alignment branch from 57a6398 to 9212914 Compare July 29, 2026 19:19
@pmachapman
pmachapman merged commit c885316 into main Jul 29, 2026
1 of 2 checks passed
@pmachapman
pmachapman deleted the separate_translation_alignment branch July 29, 2026 19:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add separate assemblies for translation and alignment Machine engines

4 participants