1

In my current project, I am trying to implement an environment to perform simulations of different workflows in a range of programs, websites, and mobile applications. These simulation subjects can run in different environments, such as inside a docker container, inside a virtual machine, or on a remote physical node, controlled over some protocol.

I am interested in the reaction of these programs to different inputs and changing conditions, such as certain user actions, or constricted network access. These reactions should be recorded for later evaluation. To maximize code reuse among the different measurement cases, I devised the following scheme: First, an environment is selected. This defines which application is used for testing i.e. a website or an app, and where it is running, i.e. Docker or an actual device. The next step is the selection of applicable logging protocols, i.e. a container running tcpdump for Docker, or an Appium server connecting to the device. Each logging infrastructure is queried whether or not it supports logging in the specified environment, and applied accordingly.

This is where my problem lies. A tcpdump container will support everything that runs in a container but needs access to the Docker connection. It should get this from the environment, but for this, it has to cast the environment to a DockerEnvironment (or something similar). Even avoiding this cast, the logger needs to check if it even supports the environment or not. This could be done with Enums denoting the type of environment, and a map with the appropriate information stored as Object, but this seems to me as just avoiding to call the devil by its name.

I looked at this question and thought the reasoning might apply here, but I still feel like there should be a better way that I am not seeing, an idiom or pattern, or maybe my approach might just be flawed to start with.

Some code for reference here:

interface Environment {}

interface DockerEnvironment {
    public String getDockerURL();
}

interface AppiumEnvironment {
    public String getAppiumURL();
}

class WebsiteInDockerEnvironment implements DockerEnvironment, AppiumEnvironment {
    public String getDockerURL() {
        return "unix:///var/run/docker.sock";
    }

    public String getAppiumURL() {
        return "http://localhost:6060";
    }
}

interface Logger {
    boolean doesSupport(Environment environment);
}

class DockerTcpDumpLogger implements Logger {

    public DockerTcpDumpLogger(DockerEnvironment environment) {
        connectToDocker(environment.getDockerURL());
    }

    @Override
    public boolean doesSupport(Environment environment) {
        return environment instanceof DockerEnvironment;
    }
}

The idea here is that further implementations of Environment may be monitored by the DockerTcpDumpLogger.

EDIT: Although optimally I would be looking for a general "best practice" on this or similar situation, it might help to know that I am working with Java.

  • You are probably going to need to put some code here if you want meaningful answers. It would also help to know what language you are working with. – JimmyJames Aug 30 at 17:20
  • Thanks for the tip, I am working with Java and will update my question accordingly, but it might take some time to boil some code down to the essential (and readable) parts. – chb Aug 30 at 17:23
  • The short answer is that you put the parts specific to Docker in the DockerEnvironment class (or related classes). It's hard to give a more detailed answer without some classes to refer to. – JimmyJames Aug 30 at 17:31
  • I thought about doing this, but I wasn't sure if putting too much of the responsibility inside the environment was a mistake itself. You most likely are right though, I will try to think my design over with this in mind. – chb Aug 30 at 17:42
1

You could do something like this:


interface Logger {
    // Logger stuff
}

interface Environment {
    Logger getLogger();
}

class WebsiteInDockerEnvironment implements Environment {
    public String getDockerURL() {
        return "unix:///var/run/docker.sock";
    }

    public String getAppiumURL() {
        return "http://localhost:6060";
    }

    @Override
    public DockerTcpDumpLogger getLogger() {
        return new DockerTcpDumpLogger(this);
    }
}

class DockerTcpDumpLogger implements Logger {

    public DockerTcpDumpLogger(DockerEnvironment environment) {
        connectToDocker(environment.getDockerURL());
    }

    @Override
    public boolean doesSupport(Environment environment) {
        return environment instanceof DockerEnvironment;
    }
}

I removed the DockerEnvironment and AppiumEnvironment interfaces because they don't seem necessary, at least for this part. They also seem too specific but you might need them for other reasons. I would avoid creating interfaces just to have an interface.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.