I'm pretty sure I've spent more time writing blogs than contests on Codeforces. Over time, I've found plenty of rough edges. So this is a plea to the Codeforces team to fix them.
I'm effectively going to say "please redo everything" over dozens of paragraphs, but I'll hopefully make the steps to the solution tangible and clear. If this is deemed way too ambitious, few improvements are better than none.
Publication time
So I write a post in the Codeforces UI, save a draft, update it a few times, think it's ready, and publish it. I open my brand new post and see:
Totally not a useless post
By purplesyringa, history, 3 days ago, In English
Okay, wait, "3 days ago"? Oh, right, that's when I saved the first draft.
Now people open the post, see "3 days ago", see 0 upvotes, and what do they think? That's right, they think it's garbage because no one's voted positive, so they skip the article.
Maybe not everyone's like that, but that's what I thought for a while upon reading others' posts, until I tried writing my own and noticed this problem.
The fix is simple: change the time to the first time the post went public.
Drafts
I seldom write posts in Codeforces UI. The main problem is it's very easy to lose text. I write a sentence, then I accidentally click Ctrl-W, and what happens? Right, the tab just closes! Now, many browsers can restore the just-closed tab with Ctrl-Shift-T (or, if you accidentally visited a link, just click "back"). But sometimes they don't, or maybe I panic, and some people aren't even aware of its existence.
The very-light-blue rectangle at the top right of the textarea saying "Drafts" that only appears two seconds after you open the page just doesn't cut it. It's hard to find unless you already know it exists, and the delay makes you panic for two seconds even if you do. Also, drafts don't save the title, which I usually spend a while on figuring out.
Meanwhile in Sublime Text (my favorite text editor), I often write texts without hitting Ctrl-S once. If I close the editor, it just restores all tabs automagically, including ones with unsaved content. That works even if I SIGKILL it.
Please bring CF to the same level. My proposition is to:
Drop the "Save draft" button and make "Drafts" the main method.
Rename drafts to "Unpublished changes" (*not* unsaved, they are saved).
Ensure they are never dropped or mixed between posts.
Use the browser APIs to prevent closing of tabs with unsaved data (if drafts are updated every 5 seconds, this should only be triggered for a short while in rare cases).
Save the title, tags, etc., not just the body.
Drop the "Drafts" button. Instead, unpublished changes to never-published posts right should be shown right in my personal blog section (only visible to the author), and unpublished changes to published posts should automatically be loaded upon opening the topic editing pages.
Show the diff between the published version and the unpublished changes. This could be accessible with a button, or, preferably, with color.
Multi-language posts
Say I want to write a post in Russian. So I create a post, write it, save a few drafts, and then I realize I was in English mode all the time. So I click the "Switch to Russian?" button and save a new version. Now, how do I delete the faux English version so that I don't accidentally publish it? Do I replace the English draft with an empty body or something?
My advice is to give a better UI for multi-language posts. This could be as simple as two tabs, making what the button "Delete" does clear, and adding "Delete translation". If CF ever wants to support more languages, adding a tab should be easier than modifying the current UI.
[cut]
[cut]
is weird.
Firstly, it's really easy to forget, which you won't notice until you open your personal blog page. I think it's a nice idea to warn if [cut]
is unused in long posts.
As far as I can see, the way [cut]
works is this. In the blog list and on the home page, [cut]
is removed. On the post page, everything matching \s*\[cut\]\s*
is deleted.
The problem here is that removing [cut]
also removes the newlines around it. So if I write
Paragraph 1
[cut]
Paragraph 2
What I'll see in the blog is
Paragraph 1 Paragraph 2
not
Paragraph 1
Paragraph 2
Markdown
The Codeforces blog syntax is almost Markdown, which makes it really easy to write the posts in other editors. Apart from Markdown, it supports LaTeX in $...$
, which many other editors recognize too. But then there are features unique to Codeforces:
[cut]
for the cut.[user:purplesyringa]
for handles.[submission:282268551]
for submissions.[problem:1A]
for contest problems.[contest:1]
for contests.[standings:1]
for contest standings.<spoiler summary="Spoiler">Body</spoiler>
for spoilers.
Nothing but Codeforces can render them right. This uniqueness also makes it hard to remember the right syntax. Finally, not everyone is aware that contest IDs and the number after #
in the title are distinct, so using contest IDs outside URLs is prone to misuse (and saying "use the ID from the URL" is just lazy design). I propose to support alternative syntaxes for the same features:
- The first
---
should be interpreted as a cut (*and* show a horizontal ruler in the post). https://codeforces.me/profile/purplesyringa
or[purplesyringa](https://codeforces.me/profile/purplesyringa)
for handles.https://codeforces.me/contest/2014/submission/282268551
for submissions.https://codeforces.me/contest/1/problem/A
for contest problems.https://codeforces.me/contest/1
for contests.https://codeforces.me/contest/1/standings
for contest standings.<details><summary>Spoiler</summary>Body</details>
and>! Body
for spoilers.
Codeforces also supports [contest_time:1]
for contest times, but I don't think anyone types that manually, so there's no need to give it good UX.
Editor
I'm not necessarily asking to make it WYSIWYG, but some kind of inline preview would be nice. Say, this Markdown code:
## Key insight
It is well-known that the maximum flow and the minimum cut of a network have equal numerical values. But there’s more to this relationship:
**Characteristic property**. For any maximum flow $$$f$$$, an $$$s-t$$$ cut is minimal if and only if no edges in the residual graph $$$G_f$$$ cross it.
**Proof**. Every $$$s-t$$$ cut crosses $$$f$$$ by weight $$$F$$$ (the value of the flow). A cut is minimal when it crosses $$$G$$$ by weight $$$F$$$. Since $$$G = G_f + f$$$, this means the cut crosses $$$G_f$$$ by weight $$$0$$$. As $$$G_f$$$ has no negative edges, the cut must not cross any edges.
[The original post](https://codeforces.me/blog/entry/128552) provides an alternative proof based on the linear programming theory.
...could be shown in the editor as follows:
## Key insight
It is well-known that the maximum flow and the minimum cut of a network have equal numerical values. But there’s more to this relationship:
**Characteristic property**. For any maximum flow $f$, an $s-t$ cut is minimal if and only if no edges in the residual graph $G_f$ cross it.
**Proof**. Every $s-t$ cut crosses $f$ by weight $F$ (the value of the flow). A cut is minimal when it crosses $G$ by weight $F$. Since $G = G_f + f$, this means the cut crosses $G_f$ by weight $0$. As $G_f$ has no negative edges, the cut must not cross any edges.
[The original post](...) provides an alternative proof based on the linear programming theory.
This way, you still see the markup, but can also immediately ensure there are no formatting mistakes, estimate the length of the paragraph in the right font, see if you like italics or bold more in this context, compare heading sizes, and check code highlighting.
Proofreading
Right now, if I want people to proof-read my post before posting it, the only way to do that is to add them as coauthors. I can also send them raw Markdown, but that way formatting errors aren't going to be noticed.
It'd be great if we could let people read the post before publishing it, without necessarily giving them the right to modify it.
This separation of concerns will likely reduce the use of the coauthor tag to actual joint posts, so it'd be nice to show all coauthors of new posts below the title:
Using residual graphs to analyze properties among minimum cuts
By purplesyringa and -is-this-fft-, history, 6 days ago, In English
Auto comment: topic has been updated by purplesyringa
Who needs this? Personally, I always tick this checkbox off, because that comment does not have any use whatsoever. When I didn't tick it off, people sometimes even downvoted the comment (even if it was just one comment, not spam). As updating the post moves it up in Recent actions, this doesn't even help promote the post. Please remove it.
Discoverability
Posts aren't discoverable.
Recent posts are only listed in the "Recent actions" column. Why is it "actions" in the first place? When I joined Codeforces, my intuition guesses "actions" meant "submissions". I understand that it includes comment updates, but still, maybe rename it to "Hot posts" or something?
Also, the column itself is two page scrolls deep. I propose to rename the "TOP" section in the navbar to "POSTS" and to split that page into two tabs: "top" and "hot".
I also have concerns about the top post heuristic/filter. For me, the at the moment is:
- Codeforces Round 974 (Div. 3) Editorial, 7 days ago, +56
- Codeforces Round 973 (Div. 2) Editorial, 4 days ago, +101
- Sneak Peak...., 39 hours ago, +165
- Super Hard Atlassian OA | How to solve ?, 20 hours ago, +6
- Problem 973D. My editorial, 15 hours ago, +72
- AtCoder Regular Contest 184 Announcement, 3 days ago, +60
- Stories of a girl programmer, 14 hours ago, +25
- JetBrains Youth Coding Club, 20 hours ago, +60
- MATH FANS (YOUTUBE CHANNEL), 32 hours ago, +5
- Meta Hacker Cup 2024 Schedule — Introducing the Meta Hacker Cup AI Track, 3 months ago, +528
Why the hell is a more recent+upvoted post below a less recent+upvoted one? Subjectively, based entirely on the publication time and the number of upvotes, I'd guess the following order would be more fair:
- Sneak Peak...., 39 hours ago, +165
- Problem 973D. My editorial, 15 hours ago, +72
- JetBrains Youth Coding Club, 20 hours ago, +60
- Stories of a girl programmer, 14 hours ago, +25
- Codeforces Round 973 (Div. 2) Editorial, 4 days ago, +101
- AtCoder Regular Contest 184 Announcement, 3 days ago, +60
- Codeforces Round 974 (Div. 3) Editorial, 7 days ago, +56
- Super Hard Atlassian OA | How to solve ?, 20 hours ago, +6
- MATH FANS (YOUTUBE CHANNEL), 32 hours ago, +5
- Meta Hacker Cup 2024 Schedule — Introducing the Meta Hacker Cup AI Track, 3 months ago, +528
This prioritizes something the community actually likes. If I was asked to provide a formula, I'd use something like upvotes / time_since_publication
or maybe upvotes / base^time_since_publication
.
Announcement vs article vs blog
There's three main uses to Codeforces posts:
- Announcements: "Codeforces Round 1234 (Div. 1)", followed closely by editorials.
- Articles: "A simple introduction to segment trees".
- Blogs: "I found a compiler bug, check out my totally UB-free code".
If you think about it, these posts have three different functions:
- Announcements convey temporal information, they are typically useless a week after the event, and are copied from a template.
- Articles convey non-temporal information, are usually suited to be included in the catalog if of high quality, and usually expect commenters to ask questions and authors to answer them.
- Blogs request support, e.g. ask commenters to find a bug or answer a question.
It is quite naive to believe one system can cover all three use cases.
Announcements
Contest announcements and editorials crowd the "TOP" section. I go to "TOP" when I want to read interesting content, and announcements are not interesting, they are just heavily upvoted. I have never once wanted to click on an announcement in the TOP page or recent actions. I believe most people only open announcements from the first or second post on the home page. So they should stay in their lane.
Announcements aren't really posts either. They don't have a free format. All announcements look the same:
Hello, Codeforces! We're glad to invite you to take part in Codeforces Round 1234 (Div. 1), which will start on Thursday, January 1, 1970 at 00:00. You will be given 6 problems and 2 hours to solve them. Some problems will be divided into subtasks.
Please note the unusual starting time.
The problems were authored by purplesyringa, purplesyringa and purplesyringa.
We would like to thank
- Nutella for his nutella coordination;
- Red, rEd, Orange, YELLOW, purple for testing;
- MikeMirzayanov for creating Codeforces and Polygon.
Score distribution:
500 − 750 − 1000 − 1500 − (2250+750) − (1500+1500+1500)
We hope you'll like the problemset!
To someone who is trying to get into competitive programming, this doesn't tell much. What is a round? Nowhere does it say it's a competition. What is a score distribution? How is it correlated to rating? What does +
mean?
As programmers, what do we do with fixed-format data? That's right! It goes in the square hole. We use a common format for it. The post might as well be a short table saying:
Codeforces Round 1234 (Div. 1)
Date: Thursday, January 1, 1970 at 00:00 (note the unusual starting time)
Duration: 2 hours
Problem scoring:
A B C D E F 500 750 1000 1500 2250 + 750 1500 + 1500 + 1500 (2 subtasks) (3 subtasks) Brought to you by:
- Authors: purplesyringa, purplesyringa and purplesyringa;
- Coordinator: Nutella;
- Testers: Red, rEd, Orange, YELLOW, purple.
We already have the "CONTESTS" tab. Integrate the current/upcoming contests from that tab with the info in announcements, design cards with the main information and pin them on the main page. Crucially, don't make contests look like posts.
Clicking the cards would redirect to a page where you can register for the contest, see the registered participants, read the actually interesting parts of the announcement in full, and comment.
Here's another idea. All the comments under announcements are one of the following:
- Memes unrelated to the particular contest
- "First comment", "yay, my first contest", and "orz Nutella"
- Bitching about the starting time
- Occasional questions about the distribution and duration
The editorials are mostly full of memes, plus understandable questions about the solutions.
What reactions are positive and viral? In other words, what comments and what parts of the announcement trigger the engagement you want, as a problem setter? It's memes, thematic contest, and photos. Capitalize on this charm! Separating out the "metadata" enables the text of the announcement to have a lighter tone, no longer forcing it to embed certain information like the date clearly.
Cards as opposed to text enable unique styles. Sponsored contests could have custom backgrounds, colors, or animated borders. Photos and logos would look well on cards below the metadata. The uwu emoji from #971 could be put into the background of a yellow card, much like in Telegram replies, and the name of the round could be styled as "Codefoworcers Round #971". It's fun, readable, doesn't feel forceful, a good choice all around.
Articles
The reason I spent so much time talking about announcements is to separate them from posts on the main page, which in turn allows articles to be added to the feed without making it hard to find contests. My proposal is to merge the "TOP" tab into "HOME" (after ensuring only good posts actually get to TOP, see the earlier section).
This way, if all you want to do is compete, you can click a card at the top of the page, and if you want to participate in discussions, you can do that without visiting another page. This makes it clear that posts are an important part of Codeforces, and that not only contest announcements are allowed to be posted or considered worthy.
As a bonus, posts are now easily discoverable: instead of navigating to "TOP" -- which sounds more like a list of top users or something, as the same word is reused in the sidebar as "Top rated" and "Top contributors" -- you just see them immediately.
Blogs
Blogs differ from articles in their target audience. Articles are supposed to be useful to most people of a certain skill range (say tutorials, training sites, YouTube channels, polls, etc.). Blogs are more personal and less professional: personal stories and questions about problem solutions are not against the spirit of CF per se, but the home page isn't a good place for them.
For this reason, I propose to split posts into two kinds: articles and blogs. The separation is very simple: if it's an interesting contribution to many people in the community (or is otherwise important to the community), it's an article; if it's a request for the community to interact with you or a personal story, it's a blog.
Oh, and by the way, exposing cheaters isn't an interesting contribution to the community unless an innovative method is used, we really need a custom mechanism for reporting that. Ideally, any post containing the words "cheater" and "cheating" should warn the author that a blog format might be better suited for them.
An important point is how contribution and upvotes relate to articles vs blogs. At present, it is common practice to downvote users asking for help. Often, that's not because the post is of low quality; it's people going "I don't want to read this". That's fair for articles, but not blogs. Oh, and this unfairness is ingrained in Codeforces: if you hover the downvote button, it says "Vote: I don't like it". Talk about morals.
Here's how to fix this:
Solve the problem, not the symptoms. People downvote because it's hard to find good content; moving articles to "HOME" will fix that partially. Add a "BLOGS" tab in place of the "TOP" tab, listing hot blogs (basically interleave recent and top blogs) such that multiple blogs fit on the page. This makes it easier to find something interesting to you specifically. All you need is to show the title, the author, the date, the number of upvotes, and the first paragraph of the post. In the editor, ask people to phrase the essence of their request in the first paragraph. Don't ask them to add a cut manually, create one automatically.
Change the title texts of the vote buttons to "This is interesting" and "This is of poor quality". This prevents the "everything I don't like is bad" crowd from growing.
The only valid reason to downvote blogs in particlar is very low quality and going against the rules of the site (or morals). Replace the downvote button with something like 💩, confirm the downvote with an alert, and let the user report the post in the same window. It makes people think twice before downvoting, but enables Nazi posts to be hidden very quickly.
Thanks!
This is all I have in mind at the moment. These parts seem most important to me.
I'm sure many other improvements would be easier to implement yet still be useful. Please feel free to comment if you have any ideas. In particular, I'm interested to read about other writers' pet peeves.
Some of my ideas would require a partial site redesign. I'll see if I can provide one for testing soon, but I'm not sure if I'll have the concentration for that (I wrote this post in one sitting in 8 hours and I'm too tired already).
I hope you find this useful and maybe eye-opening.