public function getVariation(Experiment $experiment, $userId, $attributes = null)
    {
        $bucketingId = $this->getBucketingId($userId, $attributes);

        if (!$experiment->isExperimentRunning()) {
            $this->_logger->log(Logger::INFO, sprintf('Experiment "%s" is not running.', $experiment->getKey()));
            return null;
        }

        // check if a forced variation is set
        $forcedVariation = $this->_projectConfig->getForcedVariation($experiment->getKey(), $userId);
        if (!is_null($forcedVariation)) {
            return $forcedVariation;
        }

        // check if the user has been whitelisted
        $variation = $this->getWhitelistedVariation($experiment, $userId);
        if (!is_null($variation)) {
            return $variation;
        }

        // check for sticky bucketing
        $userProfile = new UserProfile($userId);
        if (!is_null($this->_userProfileService)) {
            $storedUserProfile = $this->getStoredUserProfile($userId);
            if (!is_null($storedUserProfile)) {
                $userProfile = $storedUserProfile;
                $variation = $this->getStoredVariation($experiment, $userProfile);
                if (!is_null($variation)) {
                    return $variation;
                }
            }
        }

        if (!Validator::isUserInExperiment($this->_projectConfig, $experiment, $attributes, $this->_logger)) {
            $this->_logger->log(
                Logger::INFO,
                sprintf('User "%s" does not meet conditions to be in experiment "%s".', $userId, $experiment->getKey())
            );
            return null;
        }

        $variation = $this->_bucketer->bucket($this->_projectConfig, $experiment, $bucketingId, $userId);
        if (!is_null($variation)) {
            $this->saveVariation($experiment, $variation, $userProfile);
        }
        return $variation;
    }