PROJECT: README
Hi, I’m a second-year computer science undergraduate in NUS.
Overview
README is an integrated link manager and web feed aggregator application. My main contribution involved adding support for web feeds to README. RSS and Atom are common technologies of allowing an user to access updates to online content. When supported by websites, subscribing to the feed removes the need for users to manually check the website in question, offering greater convenience to the user.
Summary of contributions
Primary enhancement: I added web syndication(RSS/Atom) support in README.
-
Justification: With support for web syndication the user can subscribe to sources of content that they care about, and have the content delivered to them.
-
Highlights: This enhancement requires significant architectural changes in the base link management application. It required an in-depth analysis of design considerations.
-
Credits: The ROME library is used to the heavy lifting in parsing web feeds.
Minor enhancements
-
I added a counter in status bar showing how many entries are listed, which is a quality-of-life improvement.
Contributions to the User Guide
Given below are sections I contributed to the User Guide. They showcase my ability to write documentation targeting end-users. |
Subscribing to a feed: subscribe
Adds a feed and subscribes to its updates.
All entries in the subscribed feed will be added to the reading list.
Format: subscribe l/URL [ti/TITLE_OVERRIDE] [d/DESCRIPTION_OVERRIDE] [t/TAG]..
The |
A feed can have any number of tags (including 0). |
Examples:
-
Adds a feed whose name is “Kattis”.
subscribe l/https://open.kattis.com/rss/new-problems t/programming
The application may be unresponsive for a short while when adding entries from a large feed. |
Searching the web: bing
Searches Bing for entries that you can subsequently add.
This command also enters the Search Results context. Refer to [Results-Context] for available commands in this context.
Format: bing [KEYWORD]…
Examples:
-
Bing search the web for entries containing the
Trump
keyword-
bing Trump
-
Trump
Contributions to the Developer Guide
Given below are sections I contributed to the Developer Guide. They showcase my ability to write technical documentation and the technical depth of my contributions to the project. |
Web Feed support
To support the reading and subscription of web feeds, we decided to centralise various feed-related operations in a static class FeedUtil
.
Static class (chosen approach)
We define a new static class FeedUtil
in commons.util
.
FeedUtil
is primarily in charge of fetching a web feed from a URL and serializing its contents into an EntryBook
.
The advantage of this approach, which is why we decided to use it, is because keeping all the feed handling code in a single class restricts the dependency of ROME at the program boundary, which is more maintainable.
-
Pros: Relatively easy to write, and we minimise the number of classes that depend on the external library.
-
Cons: Increased coupling with the components that handle RSS feeds.
Ad-hoc
Another approach we can consider is to directly invoke ROME whenever we deal with web feeds.
-
Pros: Even easier to write, almost no code needed.
-
Cons: Bad cohesion, if we were to change the library for RSS parsing it requires changes in multiple components.
Extending and generalising Storage component.
Reading Entries from a web feed shares a major similarity with reading a stored EntryBook from disk. Both actions serialize an EntryBook
from a source of external data.
To apply this general observation we can consider the following design.
-
Pros: Expresses the intention of the code better with a stronger separation of concerns. Also applies interface segregation principle.
-
Cons: Large amounts of refactors and changes needed.
Multiple EntryBooks
ModelManager used to have only a single EntryBook
. However, managing feeds and archives subscription system means that we need to deal with more than a single EntryBook
.
Since we should only show a single EntryBook
at a time, we have to make model contain multiple entrybooks.
Multiple EntryBooks
To support multiple EntryBooks, we decided to have multiple differently named EntryBooks each with their own accessors.
Design considerations
-
Current choice: multiple differently named
EntryBook
’s with differently-named accessors each-
Pros: easy to implement
-
Cons: accessors are basically duplicated code
-
-
Alternative: Each
EntryBook
belongs to aModelContext
, modifiers overloaded to be context-sensitive-
Pros: less code duplication due to polymorphism
-
Cons: writing to an
EntryBook
that does not belong the current state will either involve an extra accessor (basically Alternative 1), or changing state (specificallyModel#setContext
), which is not robust.
-
We chose to implement multiple EntryBooks in parallel as it turned out that the different EntryBooks demanded slightly different behaviour, and a more polymorphic approach like that given in the alternative might overcomplicate the implementation.
Decoupling displayed EntryBook
Another task is to decouple the EntryBook
that is displayed from the ones that we added to ModelManager
.
Decoupling the displayed EntryBook
means that the following additional methods are implemented
-
ModelManager#displayEntryBook(EntryBook)
— shows theEntryBook
provided in the user interface.
Given below is an example usage scenario and how this mechanism behaves.
displayEntryBook
is used.-
The user launches the application. The
ModelManager
will default to displaying theEntryBook
which corresponds to the default (list) context. -
The user executes the
feed [valid_feed_url]
command to view a web feed. Thefeed
command fetches and parses the web feed into anEntryBook
which is used forModelManager#setSearchEntryBook
to replace the search contextEntryBook
. -
It then sets the
ModelContext
toCONTEXT_SEARCH
. In the search context theEntryBook
is read-only, and you can import links from the currently displayedEntryBook
into thelist
contextEntryBook
.
Design Considerations
With reference to Class diagram illustrating a model supporting multiple EntryBooks., we decided to have a SimpleListProperty<Entry>
called displayedEntryList
which is used to provide the base list for filteredEntries
.
The implementation of ModelManager#displayEntryBook
will then just be a displayedEntryList.setValue
. However we decided to keep displayEntryBook
a private method and not expose it via the Model
interface.
-
Current choice: Keep
displayEntryBook
private, it only gets called whenModelContext
changes.-
Pros: more defensive — a rogue command cannot easily display junk.
-
Cons: In the context of the
feed
command, where theEntryBook
used is in fact ephemeral. When theModelContext
switches away fromsearch
, the ephemeralEntryBook
still lives inModelManager
, using extra memory.
-
-
Alternative: Promote
displayEntryBook
toModel
interface so that other classes (such as various commands) could use it.-
Pros: easier implementation for some commands, slightly reduced memory usage.
-
Cons: decoupling displayed
EntryBook
fromModelContext
could allow buggy commands to placeModelManager
in an inconsistent state.
-
We chose to keep displayEntryBook
private and only invoke it on model context change since doing so is more robust and only entails a slight additional cognitive load.