A simple web app and API for asking and answering simple/stupid questions.
Cameron Taylor
Now You Know is built with a 3 tier service oriented architecture. All of the database infrastructure is stored in the nowyouknow.common
package, all of the service infrastructure is stored in the nowyouknow.service
package, and all of the front-end code is stored in service/src/main/resources/public
and served statically.
These objects are the main entities that are stored in the database. They exist in the nowyouknow.common.data
package and represent database rows. Interactions with the database are done with the nowyouknow.common.dao
package with CrudRepository interfaces. All Dao objects extend Spring's CrudRepository. Only additional methods are documented here.
- id: Long
- A unique identifier.
- name: String
- The name of the topic.
- description: String
- A short description of the topic.
- questions: List
- A list of all questions under this topic.
- findByName(name: String): Topic
- Finds a Topic object by its name.
- id: Long
- A unique identifier.
- text: String
- The question itself.
- open: Boolean
- Whether or not a question is open for being answered or edited.
- whenAsked: Date
- The point in time when the question was asked.
- topic: Topic
- The topic that the question falls under. Can be null.
- reaction: Reaction
- The reaction object for this question. Cannot be null
- answers: List
- A list of all answers for this question.
- id: Long
- A unique identifier
- text: String
- The actual answer.
- whenAnswered: Date
- The point in time when the answer was made.
- question: Question
- The question that this Answer answers. Cannot be null.
- reaction: Reaction
- The reaction object for this Answer. Cannot be null
- id: Long
- A unique identifier.
- likes: Integer
- The number of times this object was 'liked'.
- dislikes: Integer
- The number of times this object was 'disliked'.
- laughs: Integer
- The number of times this object was 'laughed'.
The MVC pattern is used in two places: service controllers and Angular's front end. The service controllers hold methods (controller) that house business logic and access the database (model) accordingly. The results of these operations are passed to the front-end (view) when they have completed.
Angular takes the resulting data from API calls and builds its own javascript objects to act as a model local to the browser. These model objects are presented in html form and controllers written in javascript handle user interactions, form validation, and communication with the service.
The pattern of dependency injection is used throughout the entire project. All java classes are valid beans and all javascript components are wrapped as appropriate angular components. This means that every object in the system can be mocked and injected into other objects according to the needs of that object. For example, when testing the controllers, the DAO objects are mocked so that they do not perform any database accesses. This allows for true unit testing that isolates the controllers' behavior.
As it stands now, there are no GoF design patterns present in the NowYouKnow codebase.
This is on purpose as there were no opportunities to leverage any of these design patterns in an appropriate fashion.
I had intended to add a Reactable
interface to use a bridge pattern, but since my Question and Answer classes needed to map directly to database tables, this was hard to do while preserving ORM (Object Relational Mapping).
The thing that I liked the best about my project was the use of dependency injection. Not only did this allow for strong and thorough unit tests, but it also allowed me to better take advantage of functionality offered by the Spring framework. The code that I wrote in this project follows "best practice" conventions closer than any other code I have written, and even though the overall project is not super complex, it is beautiful code to look at.
The most important lesson that I learned was that Software Engineering is not just writing code. I already knew this, but I never had an appreciation for just how important it is to write good documentation and testing. Writing actual system code only took about 20% of my time working on the project.
Topic, Question, and Answer objects each have a corresponding class in nowyouknow.service.results
that represents a flattened version of the object. These are the entities that are converted to/from json request bodies.
{
"id": 1,
"name": "Hitchhiker's Guide To The Galaxy"
}
{
"id": 1,
"text": "What is the answer to life, the universe, and everything?",
"open": true,
"whenAsked": 57392084732,
"topicId": 1,
"likes": 894,
"dislikes": 32,
"laughs": 123
}
{
"id": 1,
"text": "42",
"questionId": 1,
"likes": 42,
"dislikes": 0,
"laughs": 3
}
Requests to this URI are handled by TopicController.
{
"name": "New Topic"
}
Post a new topic. The name must be less than 257 characters and a topic of the same name cannot already exist in the database.
Retrieves a list of all topics.
Retrieve a single topic. The identifier can be the topic's name or id.
Retrieve a list of all questions for a given topic. The identifier can be the topic's name or id.
{
"name": "New Name"
}
Update a topic identified by {identifier}
with the body parameters. A topic with the same name cannot exist in the database.
Delete a topic. Identifier can be the id or name.
Requests to this URI are handled by QuestionController.
Requests to this URI are handled by AnswerController.