- Features
- Running the application
- Structure
- Storage
- Scalability
- IO / Environment
- Tests
- Further Improvements
You can post messages:
@bob -> It's a lovely weather today!
bob: It's a lovely weather today!
@alice -> perfect day for hiking
alice: perfect day for hiking
Read users' posts:
@bob
what did you guys think about the trailer for The Last Jedi? (2 seconds ago)
it's a lovely weather today! (5 minutes ago)
Follow users and see their feed:
@bob follows alice
bob is now following alice
@bob wall
bob: what did you guys think about the trailer for The Last Jedi? (2 seconds ago)
alice: perfect day for hiking (51 seconds ago)
bob: it's a lovely weather today! (1 minute ago)
To run the application, simply clone this repository and run the command ./hamerkop
from the project directory:
$ ./hamerkop
Welcome to Hamerkop, a Social Network simulation.
Type :help to see the list of available commands.
Hamerkop was built with simplicity and scalability in mind, trying to merge the requirements with possibility for future extension. The requirements met are:
- Console-based
- In-memory storage
- Local (all users will use the same terminal)
- No pre-defined list of users
- Create users upon first post command
- Four available commands: post, read, follow, wall
Along with the four required commands, a help
command was provided, so users can see what commands are available and how they work.
The project was divided in three main modules: Main, Env, Commands
The Main Module is responsible for fetching the user input and return the result from the input evaluation. It also contains the list of available commands. Future commands can be added by updating this list.
Env Module's main responsibility is to evaluate the user input and find a Command which can execute it.
The Commands Module holds the Action Runners, that is, the functions that will apply the user commands, such as display a list of posts or store a new post/user.
As the application is completely run in-memory, a record was created, named Env
such as follows:
data Env
= Env
{ cmds :: Commands
, users :: Users
, eTime :: UTCTime }
This record holds the list of available Commands, the list of Users and the time of the latest user-entered command.
Although the lack of a Database Management System (DBMS) has a huge negative impact in terms of scalability, the project focused on other aspects, such as the easiness of adding new commands, as well as the possibility of adding System Commands.
To implement the Commands structure, I took as inspiration the method applied in the Stack project. Therefore, each Command in Hamerkop is a record of a name, description and an ActionRunner. Using this structure, new commands can be added by simply updating the Commands list and implementing its specific ActionRunner, eliminating the need to change other functions.
Moreover, when the user enters a command, its input is parsed to an Action. The type of Action will depend on the user input:
- if the input starts with
@
, such as@bob -> hello
, it is parsed toUserAct
- if the input starts with
:
, such as:help
, it is parsed toSysAct
This structure was designed so that more commands can be added in the future, without syntax conflicts. Examples of future commands are:
<@user> unfollow <user>
<@user> remove <post>
:users
displays the list of stored users
:remove <user>
:new <user>
creates a new user without posts
The running environment, represented by the data record Env
, is evaluated and executed in terms of a State Monad.
Each time the user enters a command, the application will:
- Update the Environment's date/time;
- Evaluate the Action in the current Enviroment;
- Return the result of the evaluation along with the updated Environment;
The tests were written in HSpec as part of the development process. Although tests were written for some edge cases, such as reading posts from an unexisting user, the majority of the tests considered only successful scenarios, as requested in the Code Challenge description. Still, common unsuccessful scenarios were handled with proper messages. For example:
:remove bob
Command remove not found.
@bob wall
Oops! bob's wall seems empty.
A list of further improvements can be drawn from the current stage of the project:
- Introduce
unfollow
command; - Introduce
remove <post>
command; - Add Unique Identifiers to Users and Posts, so that future commands can operate on them;
- With more commands added, split
Commands
module so that each module handles only one Command; - Use the YAML package to create test stubs;
- Use QuickCheck to generate edge case scenarios for tests.
The introduction of a DBMS was left out of the list because persisting the user data is not part of the current goal of the project.