<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def get_variation(self, experiment_key, user_id, attributes=None):
 """ Gets variation where user will be bucketed. Args: experiment_key: Experiment for which user variation needs to be determined. user_id: ID for user. attributes: Dict representing user attributes. Returns: Variation key representing the variation the user will be bucketed in. None if user is not in experiment or if experiment is not Running. """


    if not self.is_valid:
      self.logger.error(enums.Errors.INVALID_DATAFILE.format('get_variation'))
      return None

    if not validator.is_non_empty_string(experiment_key):
      self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('experiment_key'))
      return None

    if not isinstance(user_id, string_types):
      self.logger.error(enums.Errors.INVALID_INPUT_ERROR.format('user_id'))
      return None

    experiment = self.config.get_experiment_from_key(experiment_key)
    variation_key = None

    if not experiment:
      self.logger.info('Experiment key "%s" is invalid. Not activating user "%s".' % (
        experiment_key,
        user_id
      ))
      return None

    if not self._validate_user_inputs(attributes):
      return None

    variation = self.decision_service.get_variation(experiment, user_id, attributes)
    if variation:
      variation_key = variation.key

    if self.config.is_feature_experiment(experiment.id):
      decision_notification_type = enums.DecisionNotificationTypes.FEATURE_TEST
    else:
      decision_notification_type = enums.DecisionNotificationTypes.AB_TEST

    self.notification_center.send_notifications(
      enums.NotificationTypes.DECISION,
      decision_notification_type,
      user_id,
      attributes or {},
      {
         'experiment_key': experiment_key,
         'variation_key': variation_key
      }
    )

    return variation_key