Skip to content

Commit c8962e1

Browse files
committed
refactor: [#238] fix Law of Demeter violations and implement consistent delegation
This refactoring addresses two related architectural concerns: Phase 1 - Application Layer (Law of Demeter): - Added 4 convenience methods to Environment: database_config(), tracker_config(), admin_token(), prometheus_config() - Updated docker_compose_templates.rs to use new methods instead of chaining through context - Eliminates method chaining violations like self.environment.context().user_inputs.tracker.core.database Phase 2 - Domain Layer (Consistent Delegation): - Added 13 accessor methods to EnvironmentContext for all directly-accessed fields - Updated 11 Environment methods to consistently delegate to context methods - Changes pattern from direct access (self.context.user_inputs.field) to delegation (self.context.field()) Benefits: - Single source of truth: EnvironmentContext controls field access - Better encapsulation: Environment doesn't know context's internal structure - Easier maintenance: Structural changes only affect EnvironmentContext - Consistent API: All Environment methods follow same delegation pattern - Improved testability: Can mock EnvironmentContext methods independently All 1509 tests passing, pre-commit checks passed.
1 parent a624d80 commit c8962e1

File tree

3 files changed

+117
-18
lines changed

3 files changed

+117
-18
lines changed

src/application/steps/rendering/docker_compose_templates.rs

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,7 @@ impl<S> RenderDockerComposeTemplatesStep<S> {
109109
let ports = self.build_tracker_ports();
110110

111111
// Create contexts based on database configuration
112-
let database_config = &self.environment.context().user_inputs.tracker.core.database;
112+
let database_config = self.environment.database_config();
113113
let (env_context, builder) = match database_config {
114114
DatabaseConfig::Sqlite { .. } => Self::create_sqlite_contexts(admin_token, ports),
115115
DatabaseConfig::Mysql {
@@ -147,17 +147,11 @@ impl<S> RenderDockerComposeTemplatesStep<S> {
147147
}
148148

149149
fn extract_admin_token(&self) -> String {
150-
self.environment
151-
.context()
152-
.user_inputs
153-
.tracker
154-
.http_api
155-
.admin_token
156-
.clone()
150+
self.environment.admin_token().to_string()
157151
}
158152

159153
fn build_tracker_ports(&self) -> TrackerPorts {
160-
let tracker_config = &self.environment.context().user_inputs.tracker;
154+
let tracker_config = self.environment.tracker_config();
161155
let (udp_tracker_ports, http_tracker_ports, http_api_port) =
162156
Self::extract_tracker_ports(tracker_config);
163157

@@ -212,7 +206,7 @@ impl<S> RenderDockerComposeTemplatesStep<S> {
212206
&self,
213207
builder: DockerComposeContextBuilder,
214208
) -> DockerComposeContextBuilder {
215-
if let Some(prometheus_config) = &self.environment.context().user_inputs.prometheus {
209+
if let Some(prometheus_config) = self.environment.prometheus_config() {
216210
builder.with_prometheus(prometheus_config.clone())
217211
} else {
218212
builder

src/domain/environment/context.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -282,4 +282,82 @@ impl EnvironmentContext {
282282
pub fn tofu_templates_dir(&self) -> PathBuf {
283283
self.internal_config.tofu_templates_dir()
284284
}
285+
286+
/// Returns the environment name
287+
#[must_use]
288+
pub fn name(&self) -> &EnvironmentName {
289+
&self.user_inputs.name
290+
}
291+
292+
/// Returns the instance name
293+
#[must_use]
294+
pub fn instance_name(&self) -> &crate::domain::InstanceName {
295+
&self.user_inputs.instance_name
296+
}
297+
298+
/// Returns the provider configuration
299+
#[must_use]
300+
pub fn provider_config(&self) -> &ProviderConfig {
301+
&self.user_inputs.provider_config
302+
}
303+
304+
/// Returns the SSH credentials
305+
#[must_use]
306+
pub fn ssh_credentials(&self) -> &SshCredentials {
307+
&self.user_inputs.ssh_credentials
308+
}
309+
310+
/// Returns the SSH port
311+
#[must_use]
312+
pub fn ssh_port(&self) -> u16 {
313+
self.user_inputs.ssh_port
314+
}
315+
316+
/// Returns the database configuration
317+
#[must_use]
318+
pub fn database_config(&self) -> &crate::domain::tracker::DatabaseConfig {
319+
&self.user_inputs.tracker.core.database
320+
}
321+
322+
/// Returns the tracker configuration
323+
#[must_use]
324+
pub fn tracker_config(&self) -> &crate::domain::tracker::TrackerConfig {
325+
&self.user_inputs.tracker
326+
}
327+
328+
/// Returns the admin token
329+
#[must_use]
330+
pub fn admin_token(&self) -> &str {
331+
&self.user_inputs.tracker.http_api.admin_token
332+
}
333+
334+
/// Returns the Prometheus configuration if enabled
335+
#[must_use]
336+
pub fn prometheus_config(&self) -> Option<&crate::domain::prometheus::PrometheusConfig> {
337+
self.user_inputs.prometheus.as_ref()
338+
}
339+
340+
/// Returns the build directory
341+
#[must_use]
342+
pub fn build_dir(&self) -> &PathBuf {
343+
&self.internal_config.build_dir
344+
}
345+
346+
/// Returns the data directory
347+
#[must_use]
348+
pub fn data_dir(&self) -> &PathBuf {
349+
&self.internal_config.data_dir
350+
}
351+
352+
/// Returns the instance IP address if available
353+
#[must_use]
354+
pub fn instance_ip(&self) -> Option<std::net::IpAddr> {
355+
self.runtime_outputs.instance_ip
356+
}
357+
358+
/// Returns the provision method
359+
#[must_use]
360+
pub fn provision_method(&self) -> Option<crate::domain::environment::ProvisionMethod> {
361+
self.runtime_outputs.provision_method
362+
}
285363
}

src/domain/environment/mod.rs

Lines changed: 35 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,9 @@ pub use crate::domain::tracker::{
131131
UdpTrackerConfig,
132132
};
133133

134+
// Re-export Prometheus types for convenience
135+
pub use crate::domain::prometheus::PrometheusConfig;
136+
134137
use crate::adapters::ssh::SshCredentials;
135138
use crate::domain::provider::ProviderConfig;
136139
use crate::domain::{InstanceName, ProfileName};
@@ -400,25 +403,49 @@ impl<S> Environment<S> {
400403
/// Returns the instance name for this environment
401404
#[must_use]
402405
pub fn instance_name(&self) -> &InstanceName {
403-
&self.context.user_inputs.instance_name
406+
self.context.instance_name()
404407
}
405408

406409
/// Returns the provider configuration for this environment
407410
#[must_use]
408411
pub fn provider_config(&self) -> &ProviderConfig {
409-
&self.context.user_inputs.provider_config
412+
self.context.provider_config()
410413
}
411414

412415
/// Returns the SSH credentials for this environment
413416
#[must_use]
414417
pub fn ssh_credentials(&self) -> &SshCredentials {
415-
&self.context.user_inputs.ssh_credentials
418+
self.context.ssh_credentials()
416419
}
417420

418421
/// Returns the SSH port for this environment
419422
#[must_use]
420423
pub fn ssh_port(&self) -> u16 {
421-
self.context.user_inputs.ssh_port
424+
self.context.ssh_port()
425+
}
426+
427+
/// Returns the database configuration for this environment
428+
#[must_use]
429+
pub fn database_config(&self) -> &DatabaseConfig {
430+
self.context.database_config()
431+
}
432+
433+
/// Returns the tracker configuration for this environment
434+
#[must_use]
435+
pub fn tracker_config(&self) -> &TrackerConfig {
436+
self.context.tracker_config()
437+
}
438+
439+
/// Returns the admin token for the HTTP API
440+
#[must_use]
441+
pub fn admin_token(&self) -> &str {
442+
self.context.admin_token()
443+
}
444+
445+
/// Returns the Prometheus configuration if enabled
446+
#[must_use]
447+
pub fn prometheus_config(&self) -> Option<&PrometheusConfig> {
448+
self.context.prometheus_config()
422449
}
423450

424451
/// Returns the SSH username for this environment
@@ -442,13 +469,13 @@ impl<S> Environment<S> {
442469
/// Returns the build directory for this environment
443470
#[must_use]
444471
pub fn build_dir(&self) -> &PathBuf {
445-
&self.context.internal_config.build_dir
472+
self.context.build_dir()
446473
}
447474

448475
/// Returns the data directory for this environment
449476
#[must_use]
450477
pub fn data_dir(&self) -> &PathBuf {
451-
&self.context.internal_config.data_dir
478+
self.context.data_dir()
452479
}
453480

454481
/// Returns the instance IP address if available
@@ -496,7 +523,7 @@ impl<S> Environment<S> {
496523
/// ```
497524
#[must_use]
498525
pub fn instance_ip(&self) -> Option<IpAddr> {
499-
self.context.runtime_outputs.instance_ip
526+
self.context.instance_ip()
500527
}
501528

502529
/// Returns the provision method for this environment
@@ -511,7 +538,7 @@ impl<S> Environment<S> {
511538
/// The provision method, if set.
512539
#[must_use]
513540
pub fn provision_method(&self) -> Option<ProvisionMethod> {
514-
self.context.runtime_outputs.provision_method
541+
self.context.provision_method()
515542
}
516543

517544
/// Returns whether this environment's infrastructure is managed by this tool

0 commit comments

Comments
 (0)