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

Refactoring #352

Merged
merged 17 commits into from
May 25, 2021
Merged

Refactoring #352

merged 17 commits into from
May 25, 2021

Conversation

burhanrashid52
Copy link
Owner

No description provided.

@burhanrashid52 burhanrashid52 marked this pull request as draft May 18, 2021 03:43
@burhanrashid52 burhanrashid52 linked an issue May 18, 2021 that may be closed by this pull request
10 tasks
@burhanrashid52 burhanrashid52 marked this pull request as ready for review May 19, 2021 12:54
@burhanrashid52
Copy link
Owner Author

@lucianocheng @tanoDxyz Can you please review it.

@tanoDxyz
Copy link
Contributor

@lucianocheng @tanoDxyz Can you please review it.

sure

@lucianocheng
Copy link
Collaborator

Will look this weekend!

Copy link
Contributor

@tanoDxyz tanoDxyz left a comment

Choose a reason for hiding this comment

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

All clear

Copy link
Contributor

@tanoDxyz tanoDxyz left a comment

Choose a reason for hiding this comment

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

Two method declarations needs attention

Copy link
Collaborator

@lucianocheng lucianocheng left a comment

Choose a reason for hiding this comment

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

Took a look. Overall looks good.

I do think we should stop and consider how the helpers and abstract classes should work re: Graphic et al. If we want to add functionality in the future, or begin to expose more things to the user, we should be clear where it should go.

* @author <https://github.com/burhanrashid52>
*/
class GraphicHelper {
private final ViewGroup mViewGroup;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Clarifying Question: Could you clarify the general purpose of GraphicHelper? By my read, it could be any / all of the below:

  • To move operational logic out of Graphic abstract class and it's subclasses?
  • To eventually expose to the user as an interface?
  • To deal exclusively with the "helper" box?

I like the idea of having a "Graphic" object, but it looks like here we're using both an Abstract class (class Graphic) and a Helper class. This is essentially using both inheritance and composition.

In other projects, I tend to see people stick to either inheritance or composition for a set of types (here: Graphic and it's subclasses). Generally I prefer composition over inheritance (see: Effective Java, Item 16), or inheritance from an interface, but I could see the argument here for either.

Would like more information to render a opinion for the review. Thanks.

Copy link
Owner Author

Choose a reason for hiding this comment

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

My initial thought was the same. I extracted GraphicHelper exclusively to deal with the helper box. But then I thought of giving a generic name that might be used in the future to handle more cases related to these boxes. I understand your point in mixing two concepts In graphics.

Maybe I can move the GraphicHelper outside the Graphics and rename it as BoxHelper. Would it make sense?

I was having two thoughts on whether to keep Graphic as an abstract class or interface. That's why I needed a third-person opinion. I personally like to have a Graphic interface. But we have a repetitive view creation and listener logic that can be converted into Template Pattern using abstract class.

I tried first with the interface and was not happy with the result and hence abstract class made sense to me. Just thinking out loud maybe we can use both abstract and interface Example: Sticker extends Graphics implements IGraphic Thoughts?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Maybe I can move the GraphicHelper outside the Graphics and rename it as BoxHelper. Would it make sense?

Thank you for doing this. BoxHelper is a better name IMO.

I was having two thoughts on whether to keep Graphic as an abstract class or interface. That's why I needed a third-person opinion. I personally like to have a Graphic interface. But we have a repetitive view creation and listener logic that can be converted into Template Pattern using abstract class.

Yep. Speaking strictly for myself, I've found using Abstract classes and a Template Pattern can degrade if the complexity grows. Specifically, if there is a lot of needed functionality, or a very deep tree of types, the abstract classes get cluttered with tons of functionality. Due to the nature of inheritance, the abstract class functionality gets included by default in every subclass. At some point the subclasses diverge on what they expect the superclass / abstract class functions to do, so there's proliferation. In the end it can result in a lot of tangling.

Note this isn't the case if the abstract class is an interface to a 3rd party, where the definitions are fixed and compliance with the template "contract" helps keep the user / library interface clean.

In this case, it's not complex enough to merit more work. Since this is strictly internal, we can switch the approach if it gets out of hand.

I tried first with the interface and was not happy with the result and hence abstract class made sense to me. Just thinking out loud maybe we can use both abstract and interface Example: Sticker extends Graphics implements IGraphic Thoughts?

Since none of this is exposed to the user, I'm fine leaving it either way. If it becomes unwieldy down the line we can switch it up.

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah forgot to mention one thing: Generally speaking, Template Pattern / Abstract classes are harder to test, since inheritance trees cannot be replaced with mock objects.

Doesn't change my answer from above, just wanted to flag it.

});
}

public interface PhotoEditor {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Question: Is the purpose of turning this into an Interface to use a builder pattern, and expose limited functions to the end-user? Or is it to eventually implement different types of PhotoEditor objects?

Copy link
Owner Author

Choose a reason for hiding this comment

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

The intention is to expose limited functionality to the user and to easily mock/fake out the PhotoEditor in the test if needed

*
* @author <https://github.com/burhanrashid52>
*/
class PhotoSaverTask extends AsyncTask<String, String, PhotoSaverTask.SaveResult> {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Probably out of scope, but AsyncTask has been deprecated. On my local branch I switched to using ThreadPools.

https://blog.mindorks.com/threadpoolexecutor-in-android-8e9d22330ee3

Also stops the (highly unlikely) edge case of someone running this twice (in a threadpool, they would be queued).

Copy link
Owner Author

Choose a reason for hiding this comment

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

You are correct. This needs to be changed. The intention was here more of refactoring without changing much of internal logic. We plan this after this release.

return new SaveResult(null, mImagePath, null);
} catch (Exception e) {
e.printStackTrace();
Log.d(TAG, "Failed to save File");
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I would log this as an error (Log.e(...))

out.close();
Log.d(TAG, "Filed Saved Successfully");
return new SaveResult(null, mImagePath, null);
} catch (Exception e) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Nit: I would narrow this catch block, either by catching IOException or creating a union of exception types using the | operator. Saves you from catching and squashing things like NullPointerException.

/**
* Created by Burhanuddin Rashid on 18/05/21.
*
* @author <https://github.com/burhanrashid52>
Copy link
Collaborator

Choose a reason for hiding this comment

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

I'm not sure if we have any tests that execute the saving logic, but this might be a good opportunity to add one.

Copy link
Owner Author

Choose a reason for hiding this comment

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

I research in the past how to achieve this. But could not find a solution for it. The closest thing I found was Facebook Screenshot testing and this Airbnb article.

Copy link
Collaborator

Choose a reason for hiding this comment

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

👍 . Yea might require a lot of mocking to get this to work.

*
* @author <https://github.com/burhanrashid52>
*/
abstract class Graphic {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Complement: This is a good name for this class.

Question: Is this meant to eventually contain the brush logic as well, or just emoji/text/sticker?

Copy link
Owner Author

Choose a reason for hiding this comment

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

The brush view is created only once and stays on top of the Graphic stack. That cause a few issues #268 . So for now it's for emoji/text/sticker.


@Override
ViewType getViewType() {
return ViewType.IMAGE;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Potentially dumb question: Any reason we're not changing this to be ViewType.STICKER? Out of scope? Maybe this is exposed to the user?

Copy link
Owner Author

Choose a reason for hiding this comment

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

Yes, It's exposed to the user in OnPhotoEditorListener and hence breaks the client code.

private final GraphicManager mGraphicManager;
private final ViewGroup mPhotoEditorView;
private final PhotoEditorViewState mViewState;
private TextView txtText;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Optional: Maybe textGraphicView or graphicTextView as a identifier? or just textView?

@Override
void setupView(View rootView) {
txtText = rootView.findViewById(R.id.tvPhotoEditorText);
if (txtText != null && mDefaultTextTypeface != null) {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Complement: Glad we're adding these null checks. Gives us flexibility in the future to change the XML templates without worrying about breaking the code.

@burhanrashid52
Copy link
Owner Author

burhanrashid52 commented May 24, 2021

Took a look. Overall looks good.

I do think we should stop and consider how the helpers and abstract classes should work re: Graphic et al. If we want to add functionality in the future, or begin to expose more things to the user, we should be clear where it should go.

First of all, thanks for the review. I've replied to comments. You can resolve the conversation as per the answer. Happy to continue the discussion on other points.

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.

Refactoring
3 participants