Skip to content
This repository was archived by the owner on Nov 6, 2025. It is now read-only.

Add resolved_issue_size_distribution field - #238

Merged
danbi2990 merged 2 commits into
mainfrom
kai/stats-issue-size-distribution
Sep 15, 2025
Merged

Add resolved_issue_size_distribution field#238
danbi2990 merged 2 commits into
mainfrom
kai/stats-issue-size-distribution

Conversation

@Goder-0

@Goder-0 Goder-0 commented Sep 5, 2025

Copy link
Copy Markdown
Contributor

Close #197

Graphql Response

image

@codecov

codecov Bot commented Sep 5, 2025

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.
✅ Project coverage is 35.51%. Comparing base (4a60da4) to head (0ddcfec).
⚠️ Report is 1 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #238      +/-   ##
==========================================
+ Coverage   34.42%   35.51%   +1.08%     
==========================================
  Files          17       17              
  Lines        1008     1025      +17     
==========================================
+ Hits          347      364      +17     
  Misses        661      661              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@danbi2990
danbi2990 self-requested a review September 5, 2025 07:10

@danbi2990 danbi2990 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add a changelog entry for the new API?

Comment thread src/api/issue_stat.rs Outdated
impl TryFrom<&str> for IssueSize {
type Error = ();

fn try_from(value: &str) -> Result<Self, Self::Error> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about using the from trait, because we already added a None variant for exceptions?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. I’ve applied it.

Comment thread src/api/issue_stat.rs Outdated
Comment on lines +127 to +128
item.project_title == super::issue::TODO_LIST_PROJECT_TITLE
&& item.todo_status.as_deref() == Some(super::issue::TODO_LIST_STATUS_DONE)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems redundant because the issues are already validated as resolved.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed it.

Comment thread src/api/issue_stat.rs Outdated
.map_or(IssueSize::None, |item| {
item.todo_size
.as_deref()
.and_then(|s| IssueSize::try_from(s).ok())

@danbi2990 danbi2990 Sep 8, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about creating a HashMap<&str, usize> first and then converting it to a Vec<IssueSize>? This would allow IssueSize to drop the hash derive.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. I’ve applied it.

Comment thread src/api/issue_stat.rs Outdated
.try_into()
.expect("The number of resolved issues will not exceed i32::MAX");

let mut size_counts = HashMap::new();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Using fold would simplify the transformation.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the suggestion. I’ve applied it.

@Goder-0
Goder-0 force-pushed the kai/stats-issue-size-distribution branch 2 times, most recently from b6b8f44 to cbeb8f2 Compare September 9, 2025 03:54
@Goder-0

Goder-0 commented Sep 9, 2025

Copy link
Copy Markdown
Contributor Author

I have a suggestion regarding the implementation of the issue_stat function that could improve its performance and memory efficiency, especially when dealing with a large number of issues.

Current Approach

The current implementation processes the issues in multiple steps:

  1. It first collects all matching issues into a Vec<Issue>.
  2. It then iterates over this Vec to calculate open_issue_count.
  3. It iterates over the Vec again to create a new Vec of resolved issues.
  4. Finally, it iterates over the resolved_issues Vec to calculate the size distribution.

This approach involves multiple passes over the data and creates intermediate collections, which can be inefficient.

Proposed Improvement

We could refactor this to calculate all statistics in a single pass.

By applying the filter and then using a single .fold() operation, we can process the entire stream of issues just once. The accumulator for the fold could be a temporary struct or a tuple that holds all the necessary stats (open_issue_count, resolved_issue_count, size_counts).

Benefits

  • Performance: Avoids multiple iterations by processing the entire collection in one go.
  • Memory Efficiency: Prevents the allocation of intermediate Vec collections.

This is just a suggestion for a potential optimization, as the current code is functionally correct. Let me know what you think!

@danbi2990

Copy link
Copy Markdown
Contributor

I have a suggestion regarding the implementation of the issue_stat function that could improve its performance and memory efficiency, especially when dealing with a large number of issues.

I've thought about this as well. My idea can be illustrated as follows:

let mut stat1 = 0;
let mut stat2 = 0;

for issue in issues {
    // calculate and mutate in one pass
}

My concern is that this approach couples the calculation logic together, which reduces modularity. If we later change the calculation structure, it would be harder to refactor.

In my opinion, we should delay this discussion until the structure is more stable.

Comment thread CHANGELOG.md Outdated
Comment on lines 11 to 13
- Added `resolvedIssueSizeDistribution` field to `issueStat` query.
- Added new statistics to GraphQL API `issueStat` query. A field
`resolvedIssueCount` is added, indicating the number of resolved issues.
Currently, an issue is defined to be resolved if and only if (1) it is

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you move these entries (line 11-15) to line 23? I believe they should come after the creation of the issueStat query.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

Comment thread src/api/issue_stat.rs Outdated
Comment on lines +127 to +130
.map_or("None", |s| match s {
"XS" | "S" | "M" | "L" | "XL" => s,
_ => "None",
});

@danbi2990 danbi2990 Sep 9, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the confusion, but using HashMap<IssueSize, usize> with Hash derived seems more robust, since this match code is redundant given the From impl for IssueSize.

Could you revert to the previous code with Hash derived for IssueSize?
It will look like this:

  let size_str = issue
      .project_items
      .nodes
      .iter()
      .find(|item| item.project_title == super::issue::TODO_LIST_PROJECT_TITLE)
      .and_then(|item| item.todo_size.as_deref())
      .unwrap_or_default();
  *acc.entry(IssueSize::from(size_str)).or_insert(0) += 1;

The reason I suggested using HashMap<&str, usize> is that I only considered the fixed set of strings: XS, S, M, L, XL and blank. However, if a new size such as "XXS" is introduced, it should first be filtered by the From implementation of IssueSize before being stored in the hashmap.

Please let me know if you have other ideas.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've made a change: I used into instead of from. What do you think?

Comment thread src/api/issue_stat.rs Outdated
count,
})
.collect();
resolved_issue_size_distribution.sort_by_key(|item| item.size);

@danbi2990 danbi2990 Sep 9, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider using sort_unstable_by_key, as it has some benefits over sort_by_key. See the "Rules on Sorting" page on Notion for details.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What do you think about using a BTreeMap instead of a HashMap here? Since the data size is usually small (around 5 items), the overhead would be negligible, and it would let us remove the extra sort_by_key step for a simpler implementation.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems reasonable. 👍

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done.

@Goder-0
Goder-0 force-pushed the kai/stats-issue-size-distribution branch from cbeb8f2 to 3fe20bb Compare September 10, 2025 08:31
@Goder-0
Goder-0 force-pushed the kai/stats-issue-size-distribution branch from 3fe20bb to adc4d5d Compare September 11, 2025 07:44
Comment thread CHANGELOG.md Outdated
Comment on lines +15 to +16
- Added `resolvedIssueSizeDistribution` field to `issueStat` query, which
shows the distribution of sizes for resolved issues.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

issueStat 도 Unreleased 섹션에서 새롭게 added 된 것이므로, resolvedIssueSizeDistribution 에 관한 것은 issueStat 의 addition에 관한 것에 포함되도록 해주세요.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정했습니다.

@Goder-0
Goder-0 force-pushed the kai/stats-issue-size-distribution branch from adc4d5d to fe8ad8d Compare September 12, 2025 04:55
@danbi2990
danbi2990 merged commit a4d6075 into main Sep 15, 2025
12 checks passed
@danbi2990
danbi2990 deleted the kai/stats-issue-size-distribution branch September 15, 2025 00:01
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

통계 구현: 인원, 기간, 저장소별 할당 & resolved 이슈의 Size 분포

3 participants