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.
Oh, and what's up with "purplesyringa mentioned you in a blog entry"? Why did I get a notification about me mentioning myself?
I think because you mentioned your user name in at the start, in the "Totally not a usless post" section, like this: purplesyringa.
Yes, and I think it shouldn't have triggered a notification.
There is one more issue with drafts that I've seen confuse many people. Say you publish a post, then go edit some things and then hit "Save Draft". What happens?
Most people would assume that the public version of the blog stays as it is, but your edits are saved and you can continue working on them until you are ready to publish them too.
What actually happens is this: your blog gets hidden from public view, anyone else trying to look at it gets a message "You are not allowed to view the requested page".
Oh crap. I might have accidentally lost some of my posts that way. Thanks!
Personally, I doubt that what the title text says matters at all. People have some mental model of what an upvote or a downvote means and some title text isn't going to change that.
Your definition of blogs is quite broad (I initially thought it meant just requests for help, but your later definition also included personal stories. I assume feature requests etc. also fall under blogs) using the current Recent Actions, "Stories of a girl programmer", "Please Help Me with This USACO Problem" and "Please improve QoL for blogs" all fall under "blogs", but are of course very different.
I'm not convinced that downvoting blogs is always so invalid. Downvoting personal stories is almost always unfair. And I agree with you there — the reason posts like "This is my third contest, hope I get pupil!" get downvoted is that there is a mismatch in expectations: authors of such posts see this as their personal blog, readers see this as a public forum.
Downvoting some other blogs — I'm not sure it's so unfair. The request for help you linked is very good (it even uses $$$\le$$$ instead of <=, this is absolutely superb quality!), but others are not so good. Sometimes the author displays very little effort (for example just pasting their code and not much more). Very often, people withhold crucial information that totally changes the problem. Sometimes a problem appears in some OA and people post the same problem 4 or 5 times. These posts should get negative feedback from the community, but there is no reason to remove them from the site altogether.
"Opinion" posts are probably one area where the differences on the interpretation of downvotes are the starkest: some people see it as reasonable to downvote if they simply disagree with the opinion, others only if the arguments supporting the opinion are poor. But with both philosophies, there are blogs that should be downvoted. If I write a post saying "Codeforces Round 1234 was bad" and my arguments essentially boil down to "I lost a lot of rating", I think I deserve being downvoted, but I don't think the blog is so bad that it should be removed from the site.
In other words, I think there is a distinction between "blog is bad and should receive downvotes" and "blog is so bad that it should be removed from the site" (trolling, leaking solutions, Nazi posts as you say). The current system allows for that: downvote in the first case, downvote and report in the second case.
My assumption was that the "important" stuff is an article and the "unimportant" stuff is a blog, with the importance inferred from how many people would want to read the post.
So "Stores of a girl programmer" and "Please improve QoL for blogs" would be articles because they're "global" and writing them was quite an involved process, but "Please Help Me with This USACO Problem" would be a blog.
I realize this is not quite an objective principle, but I still think "is this going to be interesting to a lot of people in the community?" is a good enough criterion all writers can estimate. There could be mistakes, but I don't have any data on how common they would be; maybe limit articles to >= cyans and let >= oranges transform a blog to an article, plus anyone who's ever written an article can publish another one directly? Habr does something similar, seems to work for them.
As for downvotes, I tend to agree. Perhaps downvotes on blogs should just be interpreted differently? A -1 on a good faith question is disheartening, so maybe ratings in range [-9; 0] should be rounded to 0 visually? Also, contribution should be affected mostly by articles rather than blogs, so such downvotes on blogs don't decrease the contribution much (and, on the flip side, articles "costing" more would promote writing actual articles).
Ok, then it seems that my initial impression was closer to what you had in mind. But that highlights another issue: we are having trouble communicating the difference to each other. Are we really going to expect people to categorize their posts correctly?
In fact, this is already in place for comments, albeit the range is [-5, 0]. Maybe it should be extended to blogs? (And maybe Codeforces has grown, so -10 is now a better threshold).
It's not just about being disheartening, either: such rounding prevents a kind of snowball effect where people downvote already downvoted comments.
My supposed UI was thought to have two radio buttons like this:
Blog. Questions, requests for help, personal stories, or other narrow-scope posts.
Article. Tutorials, wide polls, elaborate research, or other posts interesting to the community as a whole.
I think this is quite easy to get right.
Huh, I didn't know about that. I agree with enabling this for posts too. I'm not sure about the threshold, IMO both -5 and -10 should work fine.
I would assume that everyone who writes something publicly wants it to be seen by as many people as possible. People who ask for help want others to help them, so they would prefer others to see their post. There are dozens of cases where bad "help wanted" posts just tagged everyone in top-rated or other prominent members. Do you think people who did that would mark their blogs as "less important" by themselves?
That's what the limitation that only >= cyans can post articles helps with. Maybe blue? I don't think I've seen "help wanted" posts by people of such ratings recently.
(Blogs can be promoted to articles by >= oranges, so this doesn't really limit anyone. The cutoff is quite arbitrary, mostly egoistic because I'd want to have that permission, the more common red cutoff would work too.)
Re time of publication, the best option for us currently is to delete and create a new blog, copypasting the contents. Inconvenient but at least solves the problem.
gello sir very strong can solve this question problem:930D please help idea with editorial I read not good you it can explain very much bro
I'd also love to have an actual working blog search feature. The current search box on the top right is broken and it cannot even find out anything with the suggested example search keywords, so I can only rely on Google.
Also, I hope that we have access to the WHOLE list of blogs, from the most recent to the oldest. It's really hard for me to revisit a blog again after just a few days unless I concretely remember the title or the author.