Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[부나] 1, 2단계 영화 극장 선택 제출합니다. #15

Merged
merged 41 commits into from
Apr 29, 2023

Conversation

tmdgh1592
Copy link
Member

@tmdgh1592 tmdgh1592 commented Apr 27, 2023

안녕하새요 남잭슨!
첫 리뷰어셨는데 다시 만나서 너무 반갑습니다~!
이번 미션 리뷰 잘 부탁드립니다!! 링크

- Reminder is related with notification
Copy link

@namjackson namjackson left a comment

Choose a reason for hiding this comment

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

안녕하세요 부나!
이번 미션도 잘부탁해요!
1~2단계 미션 고생하셨어요,
몇가지 코멘트 남겼으니, 확인해주세요!

Comment on lines 34 to 48
supportFragmentManager.commit {
replace(R.id.fragment_container_view, HistoryFragment.newInstance())
}
}

R.id.home -> {
supportFragmentManager.commit {
replace(R.id.fragment_container_view, HomeFragment.newInstance())
}
}

R.id.setting -> {
supportFragmentManager.commit {
replace(R.id.fragment_container_view, SettingFragment.newInstance())
}

Choose a reason for hiding this comment

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

중복 코드는 함수로 분리해 보아요!

Copy link
Member Author

Choose a reason for hiding this comment

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

별도의 함수로 분리해서 가독성과 재사용성을 높여보겠습니다!

Comment on lines 58 to 64
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
if (shouldShowRequestPermissionRationale(Manifest.permission.POST_NOTIFICATIONS)) {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
} else {
requestPermissionLauncher.launch(Manifest.permission.POST_NOTIFICATIONS)
}
}

Choose a reason for hiding this comment

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

뎁스를 더 줄여봐도 좋을거같아요!
if-else문이 동일하네요 왜일까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

이 부분은 나중에 작업하려고 남겨두고 수정하지 않은 것 같습니다 😅

앱을 처음 실행했을 때 shouldShowRequestPermissionRationale() 반환이 참일 때 권한을 요구한다면, API 30 미만에서는 권한을 거부해도 앱을 켤 때마다 계속 권한 요청을 호출할 것입니다.
그렇기 때문에 false일 때만 권한 요청을 하도록 수정하겠습니다!

private val pendingIntent = intent.let { intent ->
intent.action = PUSH_ACTION
intent.putExtra(PUSH_DATA_KEY, data)
PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE)

Choose a reason for hiding this comment

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

0은 무엇을 의미할까요?
두번째 받은 푸시는 내예약화면으로 잘보내줄까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

찾아보니 두 번째 인자는 RequestCode로, PendingIntent를 가져오기 위한 고유 식별자 역할을 한다고 합니다.
지금같은 상황에서는 0으로 고정되어 있기 때문에 2번 예약을 해도 정상적으로 동작하지 않을 것으로 기대됩니다!

아래와 같은 코드로 고유한 값으로 설정하도록 변경하였습니다.
private fun getUniqueNumber(): Int = System.currentTimeMillis().toInt()

data: T,
) {
private val alarmManager = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
private val pendingIntent = intent.let { intent ->

Choose a reason for hiding this comment

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

let을 사용한 이유는 무엇일까요? 불필요해보여요!

Copy link
Member Author

Choose a reason for hiding this comment

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

intent를 사용하여 PendingIntent를 생성하고자 위와 같이 작성하였습니다.
하지만 null 체크를 해줄 것이 아니기 때문에 아래와 같이 코드를 수정하였습니다!

 private val pendingIntent = run {
        intent.action = PUSH_ACTION
        intent.putExtra(PUSH_DATA_KEY, data)
        PendingIntent.getBroadcast(context, getUniqueNumber(), intent, PendingIntent.FLAG_IMMUTABLE)
    }

Comment on lines 32 to 35
startActivity(
Intent(requireContext(), TicketingResultActivity::class.java)
.putExtra(TicketingResultActivity.RESERVATION_KEY, item)
)

Choose a reason for hiding this comment

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

클릭이벤트시 동작을 함수로 분리해보아요!
intent를 생성하는 방법을 통일해서 일관성있도록 수정해보아요!

Copy link
Member Author

Choose a reason for hiding this comment

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

intent를 생성하는 방법을 통일하는 것을 어떤 것을 의미하시는 건가요?!
각 Activity의 companionObject로 intent() 팩토리 함수를 만드는 것도 이에 해당하는지 궁금합니다!

Comment on lines 50 to 52
fun newInstance(): HistoryFragment = historyFragment.apply {
arguments = Bundle().apply {}
}

Choose a reason for hiding this comment

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

불필요해 보이는 코드가 있어요!

Comment on lines 170 to 180
private fun startTicketingResultActivity() {
val reservation = Reservation(
movieTitle = movie.title,
movieDate = movieDate.toPresentation(),
movieTime = movieTime.toPresentation(),
ticket = ticket,
seats = pickedSeats.toPresentation(),
ticketPrice = calculateTotalPrice()
)

registerPushBroadcast(reservation)

Choose a reason for hiding this comment

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

startTicketingResultActivity라는 이름이지만, 다른 동작도 함께하고있네요!

Choose a reason for hiding this comment

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

Reservation을 따로 생성해주진 않네요!,,
Reservation을 생성해주는것도 도메인이 해야할 책임아닐까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

예약 알림 Broadcast를 보내는 함수를 따로 호출해주도록 변경하였습니다!

@tmdgh1592
Copy link
Member Author

안녕하세요 잭슨!
코드를 수정하여 다시 리뷰요청을 보냅니다 : )

페어의 리뷰를 함께 참고하여 수정하던 도중 궁금한 점이 생겨 질문을 드리고 싶습니다.
기존에는 Application에서 Preference 객체를 생성해주었는데, Application의 생명주기가 작동하지 않는 곳에서는 문제가 생길 수 있다는 글을 보았습니다.
앱을 실행하면 Application 생명주기가 무조건 실행되는 것으로 알고 있는데 이런 문제가 발생할 수 있는 상황이 어떤게 있는지 궁금합니다!
구글링을 해보았지만 적절한 답변을 얻지 못하여 질문 드립니다..!

Copy link

@namjackson namjackson left a comment

Choose a reason for hiding this comment

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

안녕하세요 부나!
피드백 적용 잘해주셨네요! 💯
몇가지 코멘트 남겼으니, 확인해주세요 😄
코멘트는 다음미션 진행하면서 참고해주세요 👍

Comment on lines +176 to +186
private fun makeReservation(): Reservation = DomainReservation.of(
movieTitle = movie.title,
year = movieDate.year,
month = movieDate.month,
day = movieDate.day,
hour = movieTime.hour,
min = movieTime.min,
ticketCount = ticket.count,
seats = pickedSeats,
price = calculateTotalPrice(),
).toPresentation()

Choose a reason for hiding this comment

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

Reservation라는 도메인 객체를 생성해주셨지만,
여전히 객체의 생성은 View로직과 섞여있는거 같아요!

"영화를 예약한다" 라는것 또한 도메인 로직이 아닐까라는 생각이 들어요!
이부분은 추가로 고민해보셔도 좋을거같아요!

Intent(requireContext(), TicketingResultActivity::class.java)
.putExtra(TicketingResultActivity.RESERVATION_KEY, item)
)
startActivity(TicketingResultActivity.intent(requireContext(), item))

Choose a reason for hiding this comment

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

함수명은 동사나 동사구로 지으면 어덜까요?

Comment on lines +20 to +21
private var instance: LocalDataStore? = null
private lateinit var preference: SharedPreferences

Choose a reason for hiding this comment

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

LocalDataStore instance와 preference 를 따로 저장한 이유가 있나요?

Copy link
Member Author

Choose a reason for hiding this comment

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

LocalDataStore 내에서 preference를 사용하고 있어서 Preference 또한 한 번만 생성하고자 따로 저장하였습니다.

import woowacourse.movie.R
import woowacourse.movie.presentation.extensions.checkPermissionTiramisu

abstract class Reminder {

Choose a reason for hiding this comment

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

Reminder라는 기능보다는,
Notification관련 클래스는 아닐까요?

네이밍을 고민해보아요!

Copy link
Member Author

Choose a reason for hiding this comment

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

다시 보니 Reminder라기엔 단순 알람을 보내는 기능만 수행하고 있네요..!
직관저긍로 푸시 알람을 보내는 역할을 한다고 알 수 있도록 변경해보겠습니다!

.setContentIntent(onClickNotification())

if (isPermissionGranted(context)) {
NotificationManagerCompat.from(context).notify(pushId, builder.build())

Choose a reason for hiding this comment

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

pushId는 무엇을 의미할까요?
동시에 여러 노티가 오게된다면 어떻게 될까요?

Copy link
Member Author

Choose a reason for hiding this comment

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

기존 노티는 제거되고 마지막 노티만 남게 되는 문제가 있습니다.
이를 사용하는 곳에서 고정값 1000을 사용하고 있었는데, 대신에 data의 hashcode를 전달하도록 변경하였습니다.
다른 data인 경우 새로운 알림이 전송되고, 동일한 데이터에 대한 노티는 리프레시되도록 하였습니다.

@@ -0,0 +1,6 @@
package com.woowacourse.data

interface DataStore {

Choose a reason for hiding this comment

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

페어의 리뷰를 함께 참고하여 수정하던 도중 궁금한 점이 생겨 질문을 드리고 싶습니다.
기존에는 Application에서 Preference 객체를 생성해주었는데, Application의 생명주기가 작동하지 않는 곳에서는 문제가 생길 수 있다는 글을 보았습니다.
앱을 실행하면 Application 생명주기가 무조건 실행되는 것으로 알고 있는데 이런 문제가 발생할 수 있는 상황이 어떤게 있는지 궁금합니다!
구글링을 해보았지만 적절한 답변을 얻지 못하여 질문 드립니다..!

앱이 실행되다면, Application이 실행되긴하지만,
Application 또한 여러 이유로 OS내에서 제거되거나, 다시 생성될 여지가 있긴해요!
물론 일반적으로 동작에는 큰 지장은 없을거지만,
Application에서 객체를 생성해주게되면, 메모리 측면이나 성능측면에서 문제가 되기도해요.
또, Application으로부터 객체를 가져오는 동작도, 어느서나 객체를 가져올수 있어 편하지만,
사용하는 클래스에서는 Application에 대한 의존이 생기게 됩니다!
이런 의존성은 관리하기도 힘들고 테스트도 힘든구조가 되곤합니다!
아마 이런 부분들을 말씀하신거같아요! :)

@namjackson namjackson merged commit e2c45bf into woowacourse:tmdgh1592 Apr 29, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants