Knowledge-based authentication using Domain-driven Design in C#












4












$begingroup$


As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



Notes about Data Protection Questions:




  • Some questions are mandatory and some are not.

  • All mandatory questions must be answered in order to validate the caller.

  • At least one non-mandatory question must be answered in order to validate the
    caller.

  • Additional non-mandatory questions can remain unanswered.

  • Each question may have multiple correct answers.


Below are before and after screen shots of the Data Protection part of the Add Call view:



Before Data Protection has been validated



After Data Protection has been validated



The current system was written five years ago and we did not attempt to use any design patterns or modern approaches (such as Domain-Driven Design) because we lacked the time and understanding.



We now have the opportunity to re-write this software and would like to follow a Domain-driven approach.



First draft of a DataProtectionQuestion entity class:



public class DataProtectionQuestion
{
public string Question { get; set; }
public IEnumerable<string> Answers { get; set; }
public bool IsRequired { get; set; }
public string Answer { get; set; }
public bool IsAnswered => !string.IsNullOrWhiteSpace(Answer);
public bool AnswerIsCorrect => Answers?.Contains(Answer) ?? false;
}


Questions that arose from this design:




  • Is this an anaemic model?

  • Is the DataProtectionQuestion entity the 'right' place to validate the answer?

  • Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?

  • Should the setters be private and should clients supply data through a constructor?

  • Should an Answer be an entity in its own right with a property for 'IsValid'?

  • How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'? (I realise the UI is not the concern of the Domain, but having the ability to choose these as answers is)


Second draft (in an attempt to answer some of the above):



public class DataProtectionAnswer
{
public DataProtectionAnswer(string answer, bool isValid)
{
Answer = answer;
IsValid = isValid;
}
public string Answer { get; private set; }
public bool IsValid { get; private set; }
}

public class DataProtectionQuestion
{
public DataProtectionQuestion(string question, bool isRequired, IEnumerable<DataProtectionAnswer> answers)
{
// validate non-null parameters?
Question = question;
IsRequired = isRequired;
Answers = answers;
}
public string Question { get; private set; }
public bool IsRequired { get; private set; }
public IEnumerable<DataProtectionAnswer> Answers { get; private set; }
public DataProtectionAnswer SelectedAnswer { get; private set; }
public bool IsAnswered => SelectedAnswer != null;
public bool AnswerIsCorrect => SelectedAnswer?.IsValid ?? false;
public void SetSelectedAnswer(DataProtectionAnswer answer)
{
// Should validate that answer is not null and contained in Answers?
SelectedAnswer = answer;
}
}


Some answers..leading to more questions?:




  • Q. Should the entity have methods like 'SetAnswer' or
    'SetAnswerIsValid'?

  • A. I have added a 'SetSelectedAnswer' method but I still don't know if this 'feels' right?

  • Q. Should the setters be private and should clients supply data through a constructor?

  • A. I don't know but that's what I've done in draft 2.

  • Q. Should an Answer be an entity in its own right with a property for 'IsValid'?

  • A. As per previous question, this is what I've done but should I have?

  • Q. How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?

  • A. I can now do this by adding an 'Unanswered' and 'Incorrect Answer' DataProtectionAnswer to the DataProtectionQuestion, but this
    'feels' wrong. Isn't this the responsibility of the Presenter?


As you can probably tell, I'm floundering and really struggling to get my head around how to model this scenario using a DDD approach. Perhaps DDD isn't right for this situation. I don't know and I feel very stupid right now!



Can anyone please offer some guidance / suggestions on a way forward / better approach?










share|improve this question







New contributor




Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
Check out our Code of Conduct.







$endgroup$

















    4












    $begingroup$


    As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



    The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



    Notes about Data Protection Questions:




    • Some questions are mandatory and some are not.

    • All mandatory questions must be answered in order to validate the caller.

    • At least one non-mandatory question must be answered in order to validate the
      caller.

    • Additional non-mandatory questions can remain unanswered.

    • Each question may have multiple correct answers.


    Below are before and after screen shots of the Data Protection part of the Add Call view:



    Before Data Protection has been validated



    After Data Protection has been validated



    The current system was written five years ago and we did not attempt to use any design patterns or modern approaches (such as Domain-Driven Design) because we lacked the time and understanding.



    We now have the opportunity to re-write this software and would like to follow a Domain-driven approach.



    First draft of a DataProtectionQuestion entity class:



    public class DataProtectionQuestion
    {
    public string Question { get; set; }
    public IEnumerable<string> Answers { get; set; }
    public bool IsRequired { get; set; }
    public string Answer { get; set; }
    public bool IsAnswered => !string.IsNullOrWhiteSpace(Answer);
    public bool AnswerIsCorrect => Answers?.Contains(Answer) ?? false;
    }


    Questions that arose from this design:




    • Is this an anaemic model?

    • Is the DataProtectionQuestion entity the 'right' place to validate the answer?

    • Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?

    • Should the setters be private and should clients supply data through a constructor?

    • Should an Answer be an entity in its own right with a property for 'IsValid'?

    • How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'? (I realise the UI is not the concern of the Domain, but having the ability to choose these as answers is)


    Second draft (in an attempt to answer some of the above):



    public class DataProtectionAnswer
    {
    public DataProtectionAnswer(string answer, bool isValid)
    {
    Answer = answer;
    IsValid = isValid;
    }
    public string Answer { get; private set; }
    public bool IsValid { get; private set; }
    }

    public class DataProtectionQuestion
    {
    public DataProtectionQuestion(string question, bool isRequired, IEnumerable<DataProtectionAnswer> answers)
    {
    // validate non-null parameters?
    Question = question;
    IsRequired = isRequired;
    Answers = answers;
    }
    public string Question { get; private set; }
    public bool IsRequired { get; private set; }
    public IEnumerable<DataProtectionAnswer> Answers { get; private set; }
    public DataProtectionAnswer SelectedAnswer { get; private set; }
    public bool IsAnswered => SelectedAnswer != null;
    public bool AnswerIsCorrect => SelectedAnswer?.IsValid ?? false;
    public void SetSelectedAnswer(DataProtectionAnswer answer)
    {
    // Should validate that answer is not null and contained in Answers?
    SelectedAnswer = answer;
    }
    }


    Some answers..leading to more questions?:




    • Q. Should the entity have methods like 'SetAnswer' or
      'SetAnswerIsValid'?

    • A. I have added a 'SetSelectedAnswer' method but I still don't know if this 'feels' right?

    • Q. Should the setters be private and should clients supply data through a constructor?

    • A. I don't know but that's what I've done in draft 2.

    • Q. Should an Answer be an entity in its own right with a property for 'IsValid'?

    • A. As per previous question, this is what I've done but should I have?

    • Q. How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?

    • A. I can now do this by adding an 'Unanswered' and 'Incorrect Answer' DataProtectionAnswer to the DataProtectionQuestion, but this
      'feels' wrong. Isn't this the responsibility of the Presenter?


    As you can probably tell, I'm floundering and really struggling to get my head around how to model this scenario using a DDD approach. Perhaps DDD isn't right for this situation. I don't know and I feel very stupid right now!



    Can anyone please offer some guidance / suggestions on a way forward / better approach?










    share|improve this question







    New contributor




    Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
    Check out our Code of Conduct.







    $endgroup$















      4












      4








      4





      $begingroup$


      As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



      The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



      Notes about Data Protection Questions:




      • Some questions are mandatory and some are not.

      • All mandatory questions must be answered in order to validate the caller.

      • At least one non-mandatory question must be answered in order to validate the
        caller.

      • Additional non-mandatory questions can remain unanswered.

      • Each question may have multiple correct answers.


      Below are before and after screen shots of the Data Protection part of the Add Call view:



      Before Data Protection has been validated



      After Data Protection has been validated



      The current system was written five years ago and we did not attempt to use any design patterns or modern approaches (such as Domain-Driven Design) because we lacked the time and understanding.



      We now have the opportunity to re-write this software and would like to follow a Domain-driven approach.



      First draft of a DataProtectionQuestion entity class:



      public class DataProtectionQuestion
      {
      public string Question { get; set; }
      public IEnumerable<string> Answers { get; set; }
      public bool IsRequired { get; set; }
      public string Answer { get; set; }
      public bool IsAnswered => !string.IsNullOrWhiteSpace(Answer);
      public bool AnswerIsCorrect => Answers?.Contains(Answer) ?? false;
      }


      Questions that arose from this design:




      • Is this an anaemic model?

      • Is the DataProtectionQuestion entity the 'right' place to validate the answer?

      • Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?

      • Should the setters be private and should clients supply data through a constructor?

      • Should an Answer be an entity in its own right with a property for 'IsValid'?

      • How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'? (I realise the UI is not the concern of the Domain, but having the ability to choose these as answers is)


      Second draft (in an attempt to answer some of the above):



      public class DataProtectionAnswer
      {
      public DataProtectionAnswer(string answer, bool isValid)
      {
      Answer = answer;
      IsValid = isValid;
      }
      public string Answer { get; private set; }
      public bool IsValid { get; private set; }
      }

      public class DataProtectionQuestion
      {
      public DataProtectionQuestion(string question, bool isRequired, IEnumerable<DataProtectionAnswer> answers)
      {
      // validate non-null parameters?
      Question = question;
      IsRequired = isRequired;
      Answers = answers;
      }
      public string Question { get; private set; }
      public bool IsRequired { get; private set; }
      public IEnumerable<DataProtectionAnswer> Answers { get; private set; }
      public DataProtectionAnswer SelectedAnswer { get; private set; }
      public bool IsAnswered => SelectedAnswer != null;
      public bool AnswerIsCorrect => SelectedAnswer?.IsValid ?? false;
      public void SetSelectedAnswer(DataProtectionAnswer answer)
      {
      // Should validate that answer is not null and contained in Answers?
      SelectedAnswer = answer;
      }
      }


      Some answers..leading to more questions?:




      • Q. Should the entity have methods like 'SetAnswer' or
        'SetAnswerIsValid'?

      • A. I have added a 'SetSelectedAnswer' method but I still don't know if this 'feels' right?

      • Q. Should the setters be private and should clients supply data through a constructor?

      • A. I don't know but that's what I've done in draft 2.

      • Q. Should an Answer be an entity in its own right with a property for 'IsValid'?

      • A. As per previous question, this is what I've done but should I have?

      • Q. How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?

      • A. I can now do this by adding an 'Unanswered' and 'Incorrect Answer' DataProtectionAnswer to the DataProtectionQuestion, but this
        'feels' wrong. Isn't this the responsibility of the Presenter?


      As you can probably tell, I'm floundering and really struggling to get my head around how to model this scenario using a DDD approach. Perhaps DDD isn't right for this situation. I don't know and I feel very stupid right now!



      Can anyone please offer some guidance / suggestions on a way forward / better approach?










      share|improve this question







      New contributor




      Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.







      $endgroup$




      As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



      The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



      Notes about Data Protection Questions:




      • Some questions are mandatory and some are not.

      • All mandatory questions must be answered in order to validate the caller.

      • At least one non-mandatory question must be answered in order to validate the
        caller.

      • Additional non-mandatory questions can remain unanswered.

      • Each question may have multiple correct answers.


      Below are before and after screen shots of the Data Protection part of the Add Call view:



      Before Data Protection has been validated



      After Data Protection has been validated



      The current system was written five years ago and we did not attempt to use any design patterns or modern approaches (such as Domain-Driven Design) because we lacked the time and understanding.



      We now have the opportunity to re-write this software and would like to follow a Domain-driven approach.



      First draft of a DataProtectionQuestion entity class:



      public class DataProtectionQuestion
      {
      public string Question { get; set; }
      public IEnumerable<string> Answers { get; set; }
      public bool IsRequired { get; set; }
      public string Answer { get; set; }
      public bool IsAnswered => !string.IsNullOrWhiteSpace(Answer);
      public bool AnswerIsCorrect => Answers?.Contains(Answer) ?? false;
      }


      Questions that arose from this design:




      • Is this an anaemic model?

      • Is the DataProtectionQuestion entity the 'right' place to validate the answer?

      • Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?

      • Should the setters be private and should clients supply data through a constructor?

      • Should an Answer be an entity in its own right with a property for 'IsValid'?

      • How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'? (I realise the UI is not the concern of the Domain, but having the ability to choose these as answers is)


      Second draft (in an attempt to answer some of the above):



      public class DataProtectionAnswer
      {
      public DataProtectionAnswer(string answer, bool isValid)
      {
      Answer = answer;
      IsValid = isValid;
      }
      public string Answer { get; private set; }
      public bool IsValid { get; private set; }
      }

      public class DataProtectionQuestion
      {
      public DataProtectionQuestion(string question, bool isRequired, IEnumerable<DataProtectionAnswer> answers)
      {
      // validate non-null parameters?
      Question = question;
      IsRequired = isRequired;
      Answers = answers;
      }
      public string Question { get; private set; }
      public bool IsRequired { get; private set; }
      public IEnumerable<DataProtectionAnswer> Answers { get; private set; }
      public DataProtectionAnswer SelectedAnswer { get; private set; }
      public bool IsAnswered => SelectedAnswer != null;
      public bool AnswerIsCorrect => SelectedAnswer?.IsValid ?? false;
      public void SetSelectedAnswer(DataProtectionAnswer answer)
      {
      // Should validate that answer is not null and contained in Answers?
      SelectedAnswer = answer;
      }
      }


      Some answers..leading to more questions?:




      • Q. Should the entity have methods like 'SetAnswer' or
        'SetAnswerIsValid'?

      • A. I have added a 'SetSelectedAnswer' method but I still don't know if this 'feels' right?

      • Q. Should the setters be private and should clients supply data through a constructor?

      • A. I don't know but that's what I've done in draft 2.

      • Q. Should an Answer be an entity in its own right with a property for 'IsValid'?

      • A. As per previous question, this is what I've done but should I have?

      • Q. How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?

      • A. I can now do this by adding an 'Unanswered' and 'Incorrect Answer' DataProtectionAnswer to the DataProtectionQuestion, but this
        'feels' wrong. Isn't this the responsibility of the Presenter?


      As you can probably tell, I'm floundering and really struggling to get my head around how to model this scenario using a DDD approach. Perhaps DDD isn't right for this situation. I don't know and I feel very stupid right now!



      Can anyone please offer some guidance / suggestions on a way forward / better approach?







      c# ddd






      share|improve this question







      New contributor




      Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.











      share|improve this question







      New contributor




      Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      share|improve this question




      share|improve this question






      New contributor




      Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.









      asked 3 hours ago









      Nick AdkinsonNick Adkinson

      241




      241




      New contributor




      Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.





      New contributor





      Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






      Nick Adkinson is a new contributor to this site. Take care in asking for clarification, commenting, and answering.
      Check out our Code of Conduct.






















          1 Answer
          1






          active

          oldest

          votes


















          6












          $begingroup$

          To start with, you're not doing DDD here.



          DDD (Domain-Driven Design / Development) is based around the idea that we start with the domain. We don't touch code yet—we develop the domain models on-paper (or whiteboard, whatever is preferred). Once that is done, we build the code as closely to the domain as possible. The point of DDD is that the code should mirror the domain design.



          Before we get going, I highly, highly, highly recommend this book, by Scott Wlaschin, a prominent F# developer who brings DDD into a very easy-to-understand view (the examples are F#, but they apply to C# as well): Domain Modeling made Functional



          DDD is about:





          1. Define the domain, the inputs, and the outputs. That is, as a user of the system, what does the domain need to do. Here it sounds like we have part of the domain defined:




            As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



            The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



            Notes about Data Protection Questions:




            • Some questions are mandatory and some are not.

            • All mandatory questions must be answered in order to validate the caller.

            • At least one non-mandatory question must be answered in order to validate the
              caller.

            • Additional non-mandatory questions can remain unanswered.

            • Each question may have multiple correct answers.





          2. From there, we define our types. Generally, I do DDD with F#, but it's just as applicable to C#. We model the physical domain, so here we're not modeling the questions, we're modeling the validation. That is: the user must answer various questions and prove they are knowledgeable on the claim.



            This is the root of our domain model: we need to validate some information. You have mixed multiple pieces here, so we're going to separate them a bit.



          3. After building the types, we build the work. That is, the functions. We build the types as just data-structures, then we build the functions next to encapsulate the domain rules.



          So, you've defined the domain (at least, as far as I see it) via the quoted-blurb, so what I want to do is move that into some types.



          To start with, we'll define a DataProtectionResponse (we're going to use the exact language from the domain model, the purpose of DDD is to translate the human-language into code).



          class DataProtectionResponse {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          }


          Now, we need to come up with a model for DataProtectionQuestion:



          class DataProtectionQuestion {
          public string Question { get; set; }
          public bool Required { get; set; }
          }


          As you see, we are ONLY modeling two components of the question: the actual question, and whether or not it's required. The questions themselves are a different part of the domain, they're generated as a question, and using this is how we get into building a flexible model. We can now take these same questions somewhere else, and use them as a whole other tool, assuming it needs to interact with our current domain.



          Next, we have ValidQuestionAnswer. This is going to be the answer that are valid for this particular claim:



          class ValidQuestionAnswer {
          public Response Response { get; set; }
          }


          We made this a class as we absolutely want to consider a situation where an answer might have more data to it.



          Finally, the Response. You might say, "Der Kommissar, why does that need to be a class, it's always a string?" Again, we might need to add more to this model, including functionality, so we do that by using a class.



          class Response {
          public string Value { get; set; }
          }


          So now, our domain will consume an IEnumerable<DataProtectionResponse>, but not directly.



          class DataProtection {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          }


          Why another class? Well, let's start talking functionality.



          First and foremost, the primary component of our design is that DataProtection must validate. For this to work, we need a IsValid function or property there:



          public bool IsValid => Questions.All(x => x.IsSufficient);


          Alright, so we have some concepts now. We have a IsValid that indicates if our DataProtection is valid or not, and we have decided that all of the questions must be sufficiently answered.



          Next, we need to prove that a question is sufficiently answered.



          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));


          Again, we are going to encode our actual logic: this DataProtectionResponse is sufficient if any of the ValidQuestionAnswers are acceptable with the question and response.



          Next, how do we prove they're acceptable?



          Well, the first rule is that if it's not required and there is no response, then it's valid:



          if (!question.Required && response?.IsEmpty ?? false == false)
          {
          return true;
          }


          And of course, Response.IsEmpty:



          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);


          Otherwise, we want to prove that this response and the provided response are acceptable:



          return response.Satisfies(Response);


          And this is why we made it a class right-off-the-bat: we might have more logic that goes into Satisfies that might do heuristic analysis. I.e. if you provide an address, the logic might say 123 Main St. and 123 Main St and 123 Main Street are all the same.



          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }


          Next, our Response.Satisfies:



          public bool Satisfies(Response response) => Value = response.Value;


          And viola, we're done. We've encoded the entire domain, concisely, and using the actual terms the domain considers. Only 37 lines of code:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }


          We don't have any odd logic, we don't have any conflated values: each model concerns itself with it's own work, no one else's.



          Additionally, when our domain changes now (or we have to change the satisfaction logic) we have built the flexibility in-place without needing major infrastructure rewrites. If we need to override a response, we encode that in DataProtectionResponse and modify IsSufficient.



          Finally, you could even shorten Acceptable to a single statement, since the logic is relatively straightforward:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response) =>
          (!question.Required && response?.IsEmpty ?? true) || response.Satisfies(Response);
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }




          Finally, you asked a few questions about your implementation: as you see, I ignored them, purposefully. With DDD, those questions are not things to ask about the implementation but things to ask about the domain. With DDD we do iterations of "design", "implement", "design", "implement"—all the questions you have should go in the design stage, which is where you (and the other domain experts) gather and hash-out the principles of the project.



          But, suppose I were to answer them:




          Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?




          A: That's actually a design question, do you need to override whether an answer is valid or not? (I briefly touched on that in the first part of the answer.)




          Should the setters be private and should clients supply data through a constructor?




          A: This seems like an implementation question at first glance, but if we reword it things are different: can a client change an answer? If the answer is yes, the proposed design is fine. If not, model for immutability.




          Should an Answer be an entity in its own right with a property for 'IsValid'?




          A: In my humble opinion, yes. Answers aren't a string, they're a concept. Additionally, with a base-class, you can override that for answers that are bool, DateTime, etc.




          How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?




          A: That's a design question, but my suggestion is to ditch the Valid checkbox and provide a red/green "Needs Answered", "Incorrect Answer", or "Correct Answer" state. Again, do what the domain calls for. You're mixing some concerns here, and with DDD we create a clear separation. When you have a question like this, we go back into the design stage and hash it out. (It might turn out that you must not indicate if an answer is incorrect. Compliance laws are weird.)






          share|improve this answer











          $endgroup$













          • $begingroup$
            Nice one, take my vote
            $endgroup$
            – Heslacher
            2 hours ago












          Your Answer





          StackExchange.ifUsing("editor", function () {
          return StackExchange.using("mathjaxEditing", function () {
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix) {
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          });
          });
          }, "mathjax-editing");

          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "196"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: false,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });






          Nick Adkinson is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216727%2fknowledge-based-authentication-using-domain-driven-design-in-c%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          6












          $begingroup$

          To start with, you're not doing DDD here.



          DDD (Domain-Driven Design / Development) is based around the idea that we start with the domain. We don't touch code yet—we develop the domain models on-paper (or whiteboard, whatever is preferred). Once that is done, we build the code as closely to the domain as possible. The point of DDD is that the code should mirror the domain design.



          Before we get going, I highly, highly, highly recommend this book, by Scott Wlaschin, a prominent F# developer who brings DDD into a very easy-to-understand view (the examples are F#, but they apply to C# as well): Domain Modeling made Functional



          DDD is about:





          1. Define the domain, the inputs, and the outputs. That is, as a user of the system, what does the domain need to do. Here it sounds like we have part of the domain defined:




            As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



            The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



            Notes about Data Protection Questions:




            • Some questions are mandatory and some are not.

            • All mandatory questions must be answered in order to validate the caller.

            • At least one non-mandatory question must be answered in order to validate the
              caller.

            • Additional non-mandatory questions can remain unanswered.

            • Each question may have multiple correct answers.





          2. From there, we define our types. Generally, I do DDD with F#, but it's just as applicable to C#. We model the physical domain, so here we're not modeling the questions, we're modeling the validation. That is: the user must answer various questions and prove they are knowledgeable on the claim.



            This is the root of our domain model: we need to validate some information. You have mixed multiple pieces here, so we're going to separate them a bit.



          3. After building the types, we build the work. That is, the functions. We build the types as just data-structures, then we build the functions next to encapsulate the domain rules.



          So, you've defined the domain (at least, as far as I see it) via the quoted-blurb, so what I want to do is move that into some types.



          To start with, we'll define a DataProtectionResponse (we're going to use the exact language from the domain model, the purpose of DDD is to translate the human-language into code).



          class DataProtectionResponse {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          }


          Now, we need to come up with a model for DataProtectionQuestion:



          class DataProtectionQuestion {
          public string Question { get; set; }
          public bool Required { get; set; }
          }


          As you see, we are ONLY modeling two components of the question: the actual question, and whether or not it's required. The questions themselves are a different part of the domain, they're generated as a question, and using this is how we get into building a flexible model. We can now take these same questions somewhere else, and use them as a whole other tool, assuming it needs to interact with our current domain.



          Next, we have ValidQuestionAnswer. This is going to be the answer that are valid for this particular claim:



          class ValidQuestionAnswer {
          public Response Response { get; set; }
          }


          We made this a class as we absolutely want to consider a situation where an answer might have more data to it.



          Finally, the Response. You might say, "Der Kommissar, why does that need to be a class, it's always a string?" Again, we might need to add more to this model, including functionality, so we do that by using a class.



          class Response {
          public string Value { get; set; }
          }


          So now, our domain will consume an IEnumerable<DataProtectionResponse>, but not directly.



          class DataProtection {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          }


          Why another class? Well, let's start talking functionality.



          First and foremost, the primary component of our design is that DataProtection must validate. For this to work, we need a IsValid function or property there:



          public bool IsValid => Questions.All(x => x.IsSufficient);


          Alright, so we have some concepts now. We have a IsValid that indicates if our DataProtection is valid or not, and we have decided that all of the questions must be sufficiently answered.



          Next, we need to prove that a question is sufficiently answered.



          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));


          Again, we are going to encode our actual logic: this DataProtectionResponse is sufficient if any of the ValidQuestionAnswers are acceptable with the question and response.



          Next, how do we prove they're acceptable?



          Well, the first rule is that if it's not required and there is no response, then it's valid:



          if (!question.Required && response?.IsEmpty ?? false == false)
          {
          return true;
          }


          And of course, Response.IsEmpty:



          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);


          Otherwise, we want to prove that this response and the provided response are acceptable:



          return response.Satisfies(Response);


          And this is why we made it a class right-off-the-bat: we might have more logic that goes into Satisfies that might do heuristic analysis. I.e. if you provide an address, the logic might say 123 Main St. and 123 Main St and 123 Main Street are all the same.



          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }


          Next, our Response.Satisfies:



          public bool Satisfies(Response response) => Value = response.Value;


          And viola, we're done. We've encoded the entire domain, concisely, and using the actual terms the domain considers. Only 37 lines of code:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }


          We don't have any odd logic, we don't have any conflated values: each model concerns itself with it's own work, no one else's.



          Additionally, when our domain changes now (or we have to change the satisfaction logic) we have built the flexibility in-place without needing major infrastructure rewrites. If we need to override a response, we encode that in DataProtectionResponse and modify IsSufficient.



          Finally, you could even shorten Acceptable to a single statement, since the logic is relatively straightforward:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response) =>
          (!question.Required && response?.IsEmpty ?? true) || response.Satisfies(Response);
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }




          Finally, you asked a few questions about your implementation: as you see, I ignored them, purposefully. With DDD, those questions are not things to ask about the implementation but things to ask about the domain. With DDD we do iterations of "design", "implement", "design", "implement"—all the questions you have should go in the design stage, which is where you (and the other domain experts) gather and hash-out the principles of the project.



          But, suppose I were to answer them:




          Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?




          A: That's actually a design question, do you need to override whether an answer is valid or not? (I briefly touched on that in the first part of the answer.)




          Should the setters be private and should clients supply data through a constructor?




          A: This seems like an implementation question at first glance, but if we reword it things are different: can a client change an answer? If the answer is yes, the proposed design is fine. If not, model for immutability.




          Should an Answer be an entity in its own right with a property for 'IsValid'?




          A: In my humble opinion, yes. Answers aren't a string, they're a concept. Additionally, with a base-class, you can override that for answers that are bool, DateTime, etc.




          How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?




          A: That's a design question, but my suggestion is to ditch the Valid checkbox and provide a red/green "Needs Answered", "Incorrect Answer", or "Correct Answer" state. Again, do what the domain calls for. You're mixing some concerns here, and with DDD we create a clear separation. When you have a question like this, we go back into the design stage and hash it out. (It might turn out that you must not indicate if an answer is incorrect. Compliance laws are weird.)






          share|improve this answer











          $endgroup$













          • $begingroup$
            Nice one, take my vote
            $endgroup$
            – Heslacher
            2 hours ago
















          6












          $begingroup$

          To start with, you're not doing DDD here.



          DDD (Domain-Driven Design / Development) is based around the idea that we start with the domain. We don't touch code yet—we develop the domain models on-paper (or whiteboard, whatever is preferred). Once that is done, we build the code as closely to the domain as possible. The point of DDD is that the code should mirror the domain design.



          Before we get going, I highly, highly, highly recommend this book, by Scott Wlaschin, a prominent F# developer who brings DDD into a very easy-to-understand view (the examples are F#, but they apply to C# as well): Domain Modeling made Functional



          DDD is about:





          1. Define the domain, the inputs, and the outputs. That is, as a user of the system, what does the domain need to do. Here it sounds like we have part of the domain defined:




            As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



            The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



            Notes about Data Protection Questions:




            • Some questions are mandatory and some are not.

            • All mandatory questions must be answered in order to validate the caller.

            • At least one non-mandatory question must be answered in order to validate the
              caller.

            • Additional non-mandatory questions can remain unanswered.

            • Each question may have multiple correct answers.





          2. From there, we define our types. Generally, I do DDD with F#, but it's just as applicable to C#. We model the physical domain, so here we're not modeling the questions, we're modeling the validation. That is: the user must answer various questions and prove they are knowledgeable on the claim.



            This is the root of our domain model: we need to validate some information. You have mixed multiple pieces here, so we're going to separate them a bit.



          3. After building the types, we build the work. That is, the functions. We build the types as just data-structures, then we build the functions next to encapsulate the domain rules.



          So, you've defined the domain (at least, as far as I see it) via the quoted-blurb, so what I want to do is move that into some types.



          To start with, we'll define a DataProtectionResponse (we're going to use the exact language from the domain model, the purpose of DDD is to translate the human-language into code).



          class DataProtectionResponse {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          }


          Now, we need to come up with a model for DataProtectionQuestion:



          class DataProtectionQuestion {
          public string Question { get; set; }
          public bool Required { get; set; }
          }


          As you see, we are ONLY modeling two components of the question: the actual question, and whether or not it's required. The questions themselves are a different part of the domain, they're generated as a question, and using this is how we get into building a flexible model. We can now take these same questions somewhere else, and use them as a whole other tool, assuming it needs to interact with our current domain.



          Next, we have ValidQuestionAnswer. This is going to be the answer that are valid for this particular claim:



          class ValidQuestionAnswer {
          public Response Response { get; set; }
          }


          We made this a class as we absolutely want to consider a situation where an answer might have more data to it.



          Finally, the Response. You might say, "Der Kommissar, why does that need to be a class, it's always a string?" Again, we might need to add more to this model, including functionality, so we do that by using a class.



          class Response {
          public string Value { get; set; }
          }


          So now, our domain will consume an IEnumerable<DataProtectionResponse>, but not directly.



          class DataProtection {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          }


          Why another class? Well, let's start talking functionality.



          First and foremost, the primary component of our design is that DataProtection must validate. For this to work, we need a IsValid function or property there:



          public bool IsValid => Questions.All(x => x.IsSufficient);


          Alright, so we have some concepts now. We have a IsValid that indicates if our DataProtection is valid or not, and we have decided that all of the questions must be sufficiently answered.



          Next, we need to prove that a question is sufficiently answered.



          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));


          Again, we are going to encode our actual logic: this DataProtectionResponse is sufficient if any of the ValidQuestionAnswers are acceptable with the question and response.



          Next, how do we prove they're acceptable?



          Well, the first rule is that if it's not required and there is no response, then it's valid:



          if (!question.Required && response?.IsEmpty ?? false == false)
          {
          return true;
          }


          And of course, Response.IsEmpty:



          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);


          Otherwise, we want to prove that this response and the provided response are acceptable:



          return response.Satisfies(Response);


          And this is why we made it a class right-off-the-bat: we might have more logic that goes into Satisfies that might do heuristic analysis. I.e. if you provide an address, the logic might say 123 Main St. and 123 Main St and 123 Main Street are all the same.



          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }


          Next, our Response.Satisfies:



          public bool Satisfies(Response response) => Value = response.Value;


          And viola, we're done. We've encoded the entire domain, concisely, and using the actual terms the domain considers. Only 37 lines of code:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }


          We don't have any odd logic, we don't have any conflated values: each model concerns itself with it's own work, no one else's.



          Additionally, when our domain changes now (or we have to change the satisfaction logic) we have built the flexibility in-place without needing major infrastructure rewrites. If we need to override a response, we encode that in DataProtectionResponse and modify IsSufficient.



          Finally, you could even shorten Acceptable to a single statement, since the logic is relatively straightforward:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response) =>
          (!question.Required && response?.IsEmpty ?? true) || response.Satisfies(Response);
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }




          Finally, you asked a few questions about your implementation: as you see, I ignored them, purposefully. With DDD, those questions are not things to ask about the implementation but things to ask about the domain. With DDD we do iterations of "design", "implement", "design", "implement"—all the questions you have should go in the design stage, which is where you (and the other domain experts) gather and hash-out the principles of the project.



          But, suppose I were to answer them:




          Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?




          A: That's actually a design question, do you need to override whether an answer is valid or not? (I briefly touched on that in the first part of the answer.)




          Should the setters be private and should clients supply data through a constructor?




          A: This seems like an implementation question at first glance, but if we reword it things are different: can a client change an answer? If the answer is yes, the proposed design is fine. If not, model for immutability.




          Should an Answer be an entity in its own right with a property for 'IsValid'?




          A: In my humble opinion, yes. Answers aren't a string, they're a concept. Additionally, with a base-class, you can override that for answers that are bool, DateTime, etc.




          How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?




          A: That's a design question, but my suggestion is to ditch the Valid checkbox and provide a red/green "Needs Answered", "Incorrect Answer", or "Correct Answer" state. Again, do what the domain calls for. You're mixing some concerns here, and with DDD we create a clear separation. When you have a question like this, we go back into the design stage and hash it out. (It might turn out that you must not indicate if an answer is incorrect. Compliance laws are weird.)






          share|improve this answer











          $endgroup$













          • $begingroup$
            Nice one, take my vote
            $endgroup$
            – Heslacher
            2 hours ago














          6












          6








          6





          $begingroup$

          To start with, you're not doing DDD here.



          DDD (Domain-Driven Design / Development) is based around the idea that we start with the domain. We don't touch code yet—we develop the domain models on-paper (or whiteboard, whatever is preferred). Once that is done, we build the code as closely to the domain as possible. The point of DDD is that the code should mirror the domain design.



          Before we get going, I highly, highly, highly recommend this book, by Scott Wlaschin, a prominent F# developer who brings DDD into a very easy-to-understand view (the examples are F#, but they apply to C# as well): Domain Modeling made Functional



          DDD is about:





          1. Define the domain, the inputs, and the outputs. That is, as a user of the system, what does the domain need to do. Here it sounds like we have part of the domain defined:




            As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



            The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



            Notes about Data Protection Questions:




            • Some questions are mandatory and some are not.

            • All mandatory questions must be answered in order to validate the caller.

            • At least one non-mandatory question must be answered in order to validate the
              caller.

            • Additional non-mandatory questions can remain unanswered.

            • Each question may have multiple correct answers.





          2. From there, we define our types. Generally, I do DDD with F#, but it's just as applicable to C#. We model the physical domain, so here we're not modeling the questions, we're modeling the validation. That is: the user must answer various questions and prove they are knowledgeable on the claim.



            This is the root of our domain model: we need to validate some information. You have mixed multiple pieces here, so we're going to separate them a bit.



          3. After building the types, we build the work. That is, the functions. We build the types as just data-structures, then we build the functions next to encapsulate the domain rules.



          So, you've defined the domain (at least, as far as I see it) via the quoted-blurb, so what I want to do is move that into some types.



          To start with, we'll define a DataProtectionResponse (we're going to use the exact language from the domain model, the purpose of DDD is to translate the human-language into code).



          class DataProtectionResponse {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          }


          Now, we need to come up with a model for DataProtectionQuestion:



          class DataProtectionQuestion {
          public string Question { get; set; }
          public bool Required { get; set; }
          }


          As you see, we are ONLY modeling two components of the question: the actual question, and whether or not it's required. The questions themselves are a different part of the domain, they're generated as a question, and using this is how we get into building a flexible model. We can now take these same questions somewhere else, and use them as a whole other tool, assuming it needs to interact with our current domain.



          Next, we have ValidQuestionAnswer. This is going to be the answer that are valid for this particular claim:



          class ValidQuestionAnswer {
          public Response Response { get; set; }
          }


          We made this a class as we absolutely want to consider a situation where an answer might have more data to it.



          Finally, the Response. You might say, "Der Kommissar, why does that need to be a class, it's always a string?" Again, we might need to add more to this model, including functionality, so we do that by using a class.



          class Response {
          public string Value { get; set; }
          }


          So now, our domain will consume an IEnumerable<DataProtectionResponse>, but not directly.



          class DataProtection {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          }


          Why another class? Well, let's start talking functionality.



          First and foremost, the primary component of our design is that DataProtection must validate. For this to work, we need a IsValid function or property there:



          public bool IsValid => Questions.All(x => x.IsSufficient);


          Alright, so we have some concepts now. We have a IsValid that indicates if our DataProtection is valid or not, and we have decided that all of the questions must be sufficiently answered.



          Next, we need to prove that a question is sufficiently answered.



          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));


          Again, we are going to encode our actual logic: this DataProtectionResponse is sufficient if any of the ValidQuestionAnswers are acceptable with the question and response.



          Next, how do we prove they're acceptable?



          Well, the first rule is that if it's not required and there is no response, then it's valid:



          if (!question.Required && response?.IsEmpty ?? false == false)
          {
          return true;
          }


          And of course, Response.IsEmpty:



          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);


          Otherwise, we want to prove that this response and the provided response are acceptable:



          return response.Satisfies(Response);


          And this is why we made it a class right-off-the-bat: we might have more logic that goes into Satisfies that might do heuristic analysis. I.e. if you provide an address, the logic might say 123 Main St. and 123 Main St and 123 Main Street are all the same.



          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }


          Next, our Response.Satisfies:



          public bool Satisfies(Response response) => Value = response.Value;


          And viola, we're done. We've encoded the entire domain, concisely, and using the actual terms the domain considers. Only 37 lines of code:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }


          We don't have any odd logic, we don't have any conflated values: each model concerns itself with it's own work, no one else's.



          Additionally, when our domain changes now (or we have to change the satisfaction logic) we have built the flexibility in-place without needing major infrastructure rewrites. If we need to override a response, we encode that in DataProtectionResponse and modify IsSufficient.



          Finally, you could even shorten Acceptable to a single statement, since the logic is relatively straightforward:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response) =>
          (!question.Required && response?.IsEmpty ?? true) || response.Satisfies(Response);
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }




          Finally, you asked a few questions about your implementation: as you see, I ignored them, purposefully. With DDD, those questions are not things to ask about the implementation but things to ask about the domain. With DDD we do iterations of "design", "implement", "design", "implement"—all the questions you have should go in the design stage, which is where you (and the other domain experts) gather and hash-out the principles of the project.



          But, suppose I were to answer them:




          Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?




          A: That's actually a design question, do you need to override whether an answer is valid or not? (I briefly touched on that in the first part of the answer.)




          Should the setters be private and should clients supply data through a constructor?




          A: This seems like an implementation question at first glance, but if we reword it things are different: can a client change an answer? If the answer is yes, the proposed design is fine. If not, model for immutability.




          Should an Answer be an entity in its own right with a property for 'IsValid'?




          A: In my humble opinion, yes. Answers aren't a string, they're a concept. Additionally, with a base-class, you can override that for answers that are bool, DateTime, etc.




          How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?




          A: That's a design question, but my suggestion is to ditch the Valid checkbox and provide a red/green "Needs Answered", "Incorrect Answer", or "Correct Answer" state. Again, do what the domain calls for. You're mixing some concerns here, and with DDD we create a clear separation. When you have a question like this, we go back into the design stage and hash it out. (It might turn out that you must not indicate if an answer is incorrect. Compliance laws are weird.)






          share|improve this answer











          $endgroup$



          To start with, you're not doing DDD here.



          DDD (Domain-Driven Design / Development) is based around the idea that we start with the domain. We don't touch code yet—we develop the domain models on-paper (or whiteboard, whatever is preferred). Once that is done, we build the code as closely to the domain as possible. The point of DDD is that the code should mirror the domain design.



          Before we get going, I highly, highly, highly recommend this book, by Scott Wlaschin, a prominent F# developer who brings DDD into a very easy-to-understand view (the examples are F#, but they apply to C# as well): Domain Modeling made Functional



          DDD is about:





          1. Define the domain, the inputs, and the outputs. That is, as a user of the system, what does the domain need to do. Here it sounds like we have part of the domain defined:




            As part of an insurance claims system we have created, the claims managers can log incoming telephone calls relating to a claim.



            The claims manager must validate the caller by asking a number of 'Data Protection' questions that are generated dynamically from information stored against the claim in a database. I believe this type of security is known as 'knowledge-based authentication'.



            Notes about Data Protection Questions:




            • Some questions are mandatory and some are not.

            • All mandatory questions must be answered in order to validate the caller.

            • At least one non-mandatory question must be answered in order to validate the
              caller.

            • Additional non-mandatory questions can remain unanswered.

            • Each question may have multiple correct answers.





          2. From there, we define our types. Generally, I do DDD with F#, but it's just as applicable to C#. We model the physical domain, so here we're not modeling the questions, we're modeling the validation. That is: the user must answer various questions and prove they are knowledgeable on the claim.



            This is the root of our domain model: we need to validate some information. You have mixed multiple pieces here, so we're going to separate them a bit.



          3. After building the types, we build the work. That is, the functions. We build the types as just data-structures, then we build the functions next to encapsulate the domain rules.



          So, you've defined the domain (at least, as far as I see it) via the quoted-blurb, so what I want to do is move that into some types.



          To start with, we'll define a DataProtectionResponse (we're going to use the exact language from the domain model, the purpose of DDD is to translate the human-language into code).



          class DataProtectionResponse {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          }


          Now, we need to come up with a model for DataProtectionQuestion:



          class DataProtectionQuestion {
          public string Question { get; set; }
          public bool Required { get; set; }
          }


          As you see, we are ONLY modeling two components of the question: the actual question, and whether or not it's required. The questions themselves are a different part of the domain, they're generated as a question, and using this is how we get into building a flexible model. We can now take these same questions somewhere else, and use them as a whole other tool, assuming it needs to interact with our current domain.



          Next, we have ValidQuestionAnswer. This is going to be the answer that are valid for this particular claim:



          class ValidQuestionAnswer {
          public Response Response { get; set; }
          }


          We made this a class as we absolutely want to consider a situation where an answer might have more data to it.



          Finally, the Response. You might say, "Der Kommissar, why does that need to be a class, it's always a string?" Again, we might need to add more to this model, including functionality, so we do that by using a class.



          class Response {
          public string Value { get; set; }
          }


          So now, our domain will consume an IEnumerable<DataProtectionResponse>, but not directly.



          class DataProtection {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          }


          Why another class? Well, let's start talking functionality.



          First and foremost, the primary component of our design is that DataProtection must validate. For this to work, we need a IsValid function or property there:



          public bool IsValid => Questions.All(x => x.IsSufficient);


          Alright, so we have some concepts now. We have a IsValid that indicates if our DataProtection is valid or not, and we have decided that all of the questions must be sufficiently answered.



          Next, we need to prove that a question is sufficiently answered.



          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));


          Again, we are going to encode our actual logic: this DataProtectionResponse is sufficient if any of the ValidQuestionAnswers are acceptable with the question and response.



          Next, how do we prove they're acceptable?



          Well, the first rule is that if it's not required and there is no response, then it's valid:



          if (!question.Required && response?.IsEmpty ?? false == false)
          {
          return true;
          }


          And of course, Response.IsEmpty:



          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);


          Otherwise, we want to prove that this response and the provided response are acceptable:



          return response.Satisfies(Response);


          And this is why we made it a class right-off-the-bat: we might have more logic that goes into Satisfies that might do heuristic analysis. I.e. if you provide an address, the logic might say 123 Main St. and 123 Main St and 123 Main Street are all the same.



          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }


          Next, our Response.Satisfies:



          public bool Satisfies(Response response) => Value = response.Value;


          And viola, we're done. We've encoded the entire domain, concisely, and using the actual terms the domain considers. Only 37 lines of code:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response)
          {
          if (!question.Required && response?.IsEmpty ?? true)
          {
          return true;
          }

          return response.Satisfies(Response);
          }
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }


          We don't have any odd logic, we don't have any conflated values: each model concerns itself with it's own work, no one else's.



          Additionally, when our domain changes now (or we have to change the satisfaction logic) we have built the flexibility in-place without needing major infrastructure rewrites. If we need to override a response, we encode that in DataProtectionResponse and modify IsSufficient.



          Finally, you could even shorten Acceptable to a single statement, since the logic is relatively straightforward:



          class Response
          {
          public string Value { get; set; }
          public bool IsEmpty => String.IsNullOrWhiteSpace(Value);

          public bool Satisfies(Response response) => Value == response.Value;
          }
          class ValidQuestionAnswer
          {
          public Response Response { get; set; }

          public bool Acceptable(DataProtectionQuestion question, Response response) =>
          (!question.Required && response?.IsEmpty ?? true) || response.Satisfies(Response);
          }
          class DataProtectionQuestion
          {
          public string Question { get; set; }
          public bool Required { get; set; }
          }
          class DataProtectionResponse
          {
          public DataProtectionQuestion Question { get; set; }
          public IEnumerable<ValidQuestionAnswer> ValidQuestionAnswers { get; set; }
          public Response Response { get; set; }
          public bool IsSufficient => ValidQuestionAnswers.Any(x => x.Acceptable(Question, Response));
          }
          class DataProtection
          {
          public IEnumerable<DataProtectionResponse> Questions { get; set; }
          public bool IsValid => Questions.All(x => x.IsSufficient);
          }




          Finally, you asked a few questions about your implementation: as you see, I ignored them, purposefully. With DDD, those questions are not things to ask about the implementation but things to ask about the domain. With DDD we do iterations of "design", "implement", "design", "implement"—all the questions you have should go in the design stage, which is where you (and the other domain experts) gather and hash-out the principles of the project.



          But, suppose I were to answer them:




          Should the entity have methods like 'SetAnswer' or 'SetAnswerIsValid'?




          A: That's actually a design question, do you need to override whether an answer is valid or not? (I briefly touched on that in the first part of the answer.)




          Should the setters be private and should clients supply data through a constructor?




          A: This seems like an implementation question at first glance, but if we reword it things are different: can a client change an answer? If the answer is yes, the proposed design is fine. If not, model for immutability.




          Should an Answer be an entity in its own right with a property for 'IsValid'?




          A: In my humble opinion, yes. Answers aren't a string, they're a concept. Additionally, with a base-class, you can override that for answers that are bool, DateTime, etc.




          How do I display answers in the UI to include 'Unanswered' and 'Incorrect Answer'?




          A: That's a design question, but my suggestion is to ditch the Valid checkbox and provide a red/green "Needs Answered", "Incorrect Answer", or "Correct Answer" state. Again, do what the domain calls for. You're mixing some concerns here, and with DDD we create a clear separation. When you have a question like this, we go back into the design stage and hash it out. (It might turn out that you must not indicate if an answer is incorrect. Compliance laws are weird.)







          share|improve this answer














          share|improve this answer



          share|improve this answer








          edited 2 hours ago

























          answered 2 hours ago









          Der KommissarDer Kommissar

          15.6k250135




          15.6k250135












          • $begingroup$
            Nice one, take my vote
            $endgroup$
            – Heslacher
            2 hours ago


















          • $begingroup$
            Nice one, take my vote
            $endgroup$
            – Heslacher
            2 hours ago
















          $begingroup$
          Nice one, take my vote
          $endgroup$
          – Heslacher
          2 hours ago




          $begingroup$
          Nice one, take my vote
          $endgroup$
          – Heslacher
          2 hours ago










          Nick Adkinson is a new contributor. Be nice, and check out our Code of Conduct.










          draft saved

          draft discarded


















          Nick Adkinson is a new contributor. Be nice, and check out our Code of Conduct.













          Nick Adkinson is a new contributor. Be nice, and check out our Code of Conduct.












          Nick Adkinson is a new contributor. Be nice, and check out our Code of Conduct.
















          Thanks for contributing an answer to Code Review Stack Exchange!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          Use MathJax to format equations. MathJax reference.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f216727%2fknowledge-based-authentication-using-domain-driven-design-in-c%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          flock() on closed filehandle LOCK_FILE at /usr/bin/apt-mirror

          Mangá

          Eduardo VII do Reino Unido