Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.
BTW, in my previous commit (and build), the Albums and Genres views were not made opaque (I simply forgot), but I have fixed that now.

I will release another build tonight with that fix, but in the current build, at least the Tracks and Artists views should be better.

Just FYI, so you don't scratch your head wondering why only those 2 views are better.
 
You, Sir, are a genius !

I made all the playlist views opaque (and also the tab group) and selected "Draws Background" for all of them. And it made a huge difference ! Scrolling is buttery smooth with small data sets and quite decent even with 1200 tracks. I had to modify how the cells are colored and the fonts and stuff, but that was trivial. Previously, the playlist had down syndrome; now, it just gets nervous.

I never thought to attack the problem from the angle of UI/rendering, because ... guess what ... I'm a back end Java developer :) I never even thought about things like transparency and how they would affect performance. That's why I was trying to look at things like caching cells in the data source ... which is what a Java server dev would look at.

I've committed the changes and released a new build with the fix. Try it out ! See the fruits of your labor :D

https://github.com/maculateConception/aural-player/blob/master/Aural.dmg?raw=true

This build is dedicated to Tobias Dunkel

Thank you :D

Simply love how quick you are in implementing changes.
For sure it is a lot smoother now. Still now as fast as I want it to. Swift can go even faster :p
Reporting back when I've done some more research.

Want it to be as smooth as this example (the amount of data seems to be irrelevant to the performance, since I guess table view by default does a good job at caching the cells):
https://developer.apple.com/library...ion/Intro.html#//apple_ref/doc/uid/TP40014547

as a side effect of studying this example I learned about core data and also came across the defer keyword which is quite useful.
 
  • Like
Reactions: 0002378
Tobias, I finally downloaded your Aural fork (test branch), because I wanted to see how you separated the views into multiple XIBs. Just to be clear, what I have to say is not intended as a criticism, so please keep that in mind; I'm just giving you my frank opinion from whatever little knowledge of programming I have.

I noticed you followed IINA's design. I saw one class in IINA which was about 2500 lines ... what does that tell you ? To be honest, I don't like it at all ... the IINA design, and how your Aural code looks after separating the XIBs.

By separating the views into multiple XIBs, the code has become rather ugly. There are WindowControllers and ViewControllers being declared as instance vars everywhere, and you have to instantiate them yourself, and what should be private methods and vars are directly accessed across controllers that should be isolated from one another.

This completely violates the separation of concerns principle ... it's mixing view handling code with instantiation of top level objects (thus resulting in larger and uglier classes), and the dependency graph is a spaghetti bowl (which violates loose coupling) ... instead of letting the application-level XIB instantiate and inject everything for you (through outlets) and letting each piece specialize in what it is concerned with and does best.

Here's one particularly ugly piece of code, to illustrate what I mean:

Code:
// This is inside PlaylistWindowController

playlistView.doubleAction = #selector(mainWindowController.playbackViewController.playSelectedTrackAction(_:))

This is very tight coupling, completely violates separation of concerns and any notion of object-oriented programming (esp. encapsulation and abstraction). First off, the window controller doesn't belong inside PlaylistWindowController. Secondly, the playlist window controller has knowledge of, and is using, what should be a private variable of mainWindowController. Furthermore, it is borrowing an action (method) from that third controller, which it has no business doing, or even knowing about. If reusability is the aim, then, that action code should be put in a utility class. The way this code is written, maintaining it will be a challenge.If the code inside playbackViewController.playSelectedTrackAction() changes, playlistWindowController will be directly affected by it.

Each window controller (or view controller) should be completely isolated from any other controller. They should pass messages back and forth, without directly invoking methods on each other like the example I pointed out, i.e. loose coupling.

In my Aural codebase, this is done via SyncMessenger and AsyncMessenger. The messaging model I follow is "publish/subscribe". That way, app components can communicate when they need to, and yet not know the most intimate details of each other. When one component changes, other components don't care, because the overall contract has not changed.

https://en.wikipedia.org/wiki/Publish–subscribe_pattern#Loose_coupling

http://everythingel.se/blog/publish-subscribe-in-swift/

I'd rather have one big monolithic XIB and MUCH cleaner code than be worrying about instantiating WindowControllers in my code. Let the XIB instantiate all my controllers, fill in all the dependencies (outlets) and let me worry only about what each piece is responsible for. I like this paradigm a lot esp. because of my experience with the Spring (Java) framework which I used when developing Java web services. Dependencies are instantiated by the framework and "injected" into your application classes so that the app classes don't have to be tightly coupled with each other. Class Foo doesn't need to know how to instantiate Class Bar (and Bar's dependencies, in turn), and accesses only the public interface of Bar.

When I said I was going to separate the big XIB into smaller XIBs, I thought that I could keep my code just as clean as it is now and just have smaller cleaner XIBs. But, I was sorely mistaken.

Now, if separating XIBs can be done in a cleaner way, and I'm sure there is one, I'm definitely interested in doing that. But, not in this way. For now, I'll stick with one XIB and clean code ... at least till I find a cleaner way to separate the XIBs.
 
Last edited:
  • Like
Reactions: Tobias_Dunkel
Thanks a lot for the feedback. Appreciate it very much :) I know that my way is the wrong one right now, since I’m aware of the best case scenario of view controllers not knowing about each other. My way of doing it was just to get the initial separation done and at least working, so I can start decoupling the view controllers one by one while being able to run and debug the app without hundreds of errors to show up.

Now I can just remove the reference of a specific controller and instantly see all the code and functions that reference to it and then replace the methods with decoupled ones, view by view.

I already did a lot of research in that direction, and since it's a pretty big topic it takes quite some time to get into it. I’m only at the very beginning I admit. At the very least, I know all the different ways of decoupling and passing data between view controllers.

At the moment I’m not 100% sure where exactly to take which approach, just that separating all views which have a dedicated view controller, is a pattern I wanna achieve. Personally I don't like it all at one place. Why would I do that instead of just using a storyboard in the first place? After all that way the .xib grows in size more and more and turning into something too complex not easy to handle, debug, or probably merge later.

By having the view controller and the corresponding .xib next to each other in the file tree you directly know the view to be controlled by the view controller. With a single xib on the other hand you cannot be sure about cross references, like you could insert a playlist button’s IBOutlet to the code of the main window. Not sure if I would call that decoupled then.

For example on your PlaybackViewController there’s also references to the playlist, to the seek slider and to a whole lot of menu bar items. How would I know that without specifically searching for it in the code or looking at the connections inspector?

Why should the PlaybackViewController even care if there is a playlist at all, as long as there are songs to be played stored in the model? Or why should it know about the seek slider?

Removing one view controller here would result in a lot of errors and since the IBOutlets do exist in the code the compiler wouldn’t even complaining for something to be missing.

Not sure if that’s the reason, but all over the net I read a separating the views is something that should be done and that a single .xib file should only have one view controller. Thus most of the time only have one view as well. You can however add panels/views with minor UI elements to the same .xib that are also managed by the same view controller. This makes the responsibilities very clear.

And at least for me, that way, it is easier to follow an applications structure and dependencies too. Plus making overall changes to the front-end can be made easily.

Last but not least by making these changes, what I want to achieve, in the end, actually is what you criticised: loose coupling between all the view controllers. And I want to do it with as less code as possible.

This is an article I read which sums up perfectly the ways to communicate between view controllers (you probably already know about all of these): https://matteomanferdini.com/how-ios-view-controllers-communicate-with-each-other/
and even though some methodes are just applicable with using Storyboards and segues, all the other methods are mentioned as well.

So how I want it all to work is:
- handle communication, where there’s stored data, through the app state/model (maybe use that in conjunction with KVO)
- using delegates where temporary data is passed on a 1 to 1 relationship (just between two view controllers)
- using notification where the first two don’t apply

First example:
I have the playback state in my model/app state.
So when the playback state ‘didset’, no matter who did it, change the playback icon to the corresponding state.

Second example:
Since the playlist is created by the main window controller, this means it has to know about the playlist. Guess that is ok in this single case. So when clicking the show in playlist button I invoke the playlists own method to highlight the playing track (which is stored in the app state). Alternatively I guess a delegate pattern would also work in that case.

After all im probably not telling you something you didn’t know already, but that’s not what I want to do here. I just want to explain myself and why im doing specific things a specific way, or where I wanna go with my branch. I’m contributing to this project to learn and I have learned so much from you already, but I’m not really good with applying decoupled comminucation between view controllers, that’s why I want to learn it by doing it. And I want to learn it not only by making use of NSNotificationCenter or referencing Objects as IBOutlets, but using all the possible ways of doing it.

Here are two very simple examples of how I want to structure the UI with separate xib. files:

1.
https://developer.apple.com/library/content/samplecode/Exhibition/Introduction/Intro.html

2.
https://www.toptal.com/ios/swift-tutorial-introduction-to-mvvm
corresponding project file:
https://bitbucket.org/dino4674/mvvmswiftexample-finished/get/892ee747f5f3.zip

Having them all separate, makes the xib. files/views:
- reusable
- easy to rearrange in a different way in case of ui changes
- easy to understand and debug
- easier to layout
- easy to grasp the responsibilities of a view

To make it clear once more, I’m not criticizing your approach in any way, I’m just explaining why I want to do it different. Not sure how long all the changes will take, but I’m sure it will bring me further in my coding abilities, which is the main reason I'm contributing to this awesome project in the first place ;)
 
  • Like
Reactions: 0002378
Thanks a lot for the feedback. Appreciate it very much :) To make it clear once more, I’m not criticizing your approach in any way, I’m just explaining why I want to do it different. Not sure how long all the changes will take, but I’m sure it will bring me further in my coding abilities, which is the main reason I'm contributing to this awesome project in the first place ;)

Hey, thanks for getting back to me. I'm drunk as a horse and it's 4.30 am so I cannot respond in detail now, but I will get back to you tomorrow.

Once again, I'm glad to be working with you on this project :)
 
  • Like
Reactions: Tobias_Dunkel
Thanks a lot for the feedback. Appreciate it very much :) I know that my way is the wrong one right now, since I’m aware of the best case scenario of view controllers not knowing about each other. My way of doing it was just to get the initial separation done and at least working, so I can start decoupling the view controllers one by one while being able to run and debug the app without hundreds of errors to show up.

Now I can just remove the reference of a specific controller and instantly see all the code and functions that reference to it and then replace the methods with decoupled ones, view by view.

I already did a lot of research in that direction, and since it's a pretty big topic it takes quite some time to get into it. I’m only at the very beginning I admit. At the very least, I know all the different ways of decoupling and passing data between view controllers.

At the moment I’m not 100% sure where exactly to take which approach, just that separating all views which have a dedicated view controller, is a pattern I wanna achieve. Personally I don't like it all at one place. Why would I do that instead of just using a storyboard in the first place? After all that way the .xib grows in size more and more and turning into something too complex not easy to handle, debug, or probably merge later.

By having the view controller and the corresponding .xib next to each other in the file tree you directly know the view to be controlled by the view controller. With a single xib on the other hand you cannot be sure about cross references, like you could insert a playlist button’s IBOutlet to the code of the main window. Not sure if I would call that decoupled then.

For example on your PlaybackViewController there’s also references to the playlist, to the seek slider and to a whole lot of menu bar items. How would I know that without specifically searching for it in the code or looking at the connections inspector?

Why should the PlaybackViewController even care if there is a playlist at all, as long as there are songs to be played stored in the model? Or why should it know about the seek slider?

Removing one view controller here would result in a lot of errors and since the IBOutlets do exist in the code the compiler wouldn’t even complaining for something to be missing.

Not sure if that’s the reason, but all over the net I read a separating the views is something that should be done and that a single .xib file should only have one view controller. Thus most of the time only have one view as well. You can however add panels/views with minor UI elements to the same .xib that are also managed by the same view controller. This makes the responsibilities very clear.

And at least for me, that way, it is easier to follow an applications structure and dependencies too. Plus making overall changes to the front-end can be made easily.

Last but not least by making these changes, what I want to achieve, in the end, actually is what you criticised: loose coupling between all the view controllers. And I want to do it with as less code as possible.

This is an article I read which sums up perfectly the ways to communicate between view controllers (you probably already know about all of these): https://matteomanferdini.com/how-ios-view-controllers-communicate-with-each-other/
and even though some methodes are just applicable with using Storyboards and segues, all the other methods are mentioned as well.

So how I want it all to work is:
- handle communication, where there’s stored data, through the app state/model (maybe use that in conjunction with KVO)
- using delegates where temporary data is passed on a 1 to 1 relationship (just between two view controllers)
- using notification where the first two don’t apply

First example:
I have the playback state in my model/app state.
So when the playback state ‘didset’, no matter who did it, change the playback icon to the corresponding state.

Second example:
Since the playlist is created by the main window controller, this means it has to know about the playlist. Guess that is ok in this single case. So when clicking the show in playlist button I invoke the playlists own method to highlight the playing track (which is stored in the app state). Alternatively I guess a delegate pattern would also work in that case.

After all im probably not telling you something you didn’t know already, but that’s not what I want to do here. I just want to explain myself and why im doing specific things a specific way, or where I wanna go with my branch. I’m contributing to this project to learn and I have learned so much from you already, but I’m not really good with applying decoupled comminucation between view controllers, that’s why I want to learn it by doing it. And I want to learn it not only by making use of NSNotificationCenter or referencing Objects as IBOutlets, but using all the possible ways of doing it.

Here are two very simple examples of how I want to structure the UI with separate xib. files:

1.
https://developer.apple.com/library/content/samplecode/Exhibition/Introduction/Intro.html

2.
https://www.toptal.com/ios/swift-tutorial-introduction-to-mvvm
corresponding project file:
https://bitbucket.org/dino4674/mvvmswiftexample-finished/get/892ee747f5f3.zip

Having them all separate, makes the xib. files/views:
- reusable
- easy to rearrange in a different way in case of ui changes
- easy to understand and debug
- easier to layout
- easy to grasp the responsibilities of a view

To make it clear once more, I’m not criticizing your approach in any way, I’m just explaining why I want to do it different. Not sure how long all the changes will take, but I’m sure it will bring me further in my coding abilities, which is the main reason I'm contributing to this awesome project in the first place ;)

Ok, so breaking your response into multiple quotes is a larger endeavor than I can manage right now, so I will respond to it in one big chunk.

Yes, I totally get your trying to get a working start ... that is how I begin any project too, and I code iteratively too. That's fine, I get it.

To answer your question about why the seek slider and certain menu items are referenced in the PlaybackViewController, you might recall me mentioning a while ago that my view controllers each handle either one "logical component" (or "aspect") of the app, or a physical one (i.e. a view). Playback is one aspect of the app, so I wanted all playback functions to be handled by PlaybackViewController. The alternative would be to put those items in controllers each responsible for one view, but send out messages to initiate playback. The irony is that, no matter which way it is done, separation of concerns is both 1 - somewhat created, and 2 - somewhat violated. I chose one way of doing it. So, whether it's a menu item, button, playlist table view, or the kitchen sink, ... if it triggers playback, it's in PlaybackViewController. That was my reasoning. Now, this may not be the MacOS/Swift way of doing things, but it makes sense to me.

So, if, at any time, you're unsure where to look for code handling a certain UI element, ask yourself, "Which aspect of the app is this control responsible for ? Playback ? Playlist CRUD ? Effects ?". That will point you to which ViewController class(es) the control will be referenced in. Example - you wanna know where the seek slider action function is ... "What happens when I move the seek slider ? The player seeks forward/backward. What aspect of the app is this ? Playback ! Let's look in PlaybackViewController. But, also, another aspect - "Now Playing Info". The seek slider's position has to be updated as playback proceeds. Which controller shows Now Playing info ? NowPlayingInfoViewController."

I am certain of two things:

1 - You have done way more research and know way more about the MacOS best practices/guidelines than I do. No question about it.
2 - There are a lot of MacOS guidelines that I am not following, partly because I'm not even aware of them.

Admittedly, I'm going about this whole project with pretty much the same approach I'd apply to a Core Java back end web service project, and that is reflected in the code I write. And, often, it directly conflicts with the MacOS way of doing things. But, there is also a lot of wisdom in that approach, because it is based in a bedrock of solid coding/design principles, and so, I don't see it as being an invalid approach, just different. MacOS best practices or Apple may not agree with it, but ... I won't lose any sleep over it. There are certain coding/design fundamentals that apply to any project, regardless of whether its a server-side Java app or a user-facing Swift app.

What I was trying to say was that I agree that the XIB should be split up ... no doubt ! And, I'm well aware of the benefits of doing so. Apart from maintainability, there is the huge advantage of a faster app startup and possibly also a smaller memory footprint ? (don't need to load preferences/sort/search dialogs ... they can be in separate XIBs and loaded lazily)

However, where I stop agreeing with that paradigm is where I see XIB instantiation code spread all over the place and one window controller accessing "private" members from another controller. I absolutely agree with what you're proposing. I'm just not agreeing with how.

The way IINA has done it (which you followed) flies in the face of tried and true OOP and general design principles I've been applying my whole career. If I have to completely abandon code cleanliness to achieve the separate XIBs, then I will steadfastly refuse to do so. In other words, any advantage gained by breaking up the big XIB is entirely lost if the code becomes as ugly as what I saw. You're completely defeating the purpose of breaking up the XIBs (i.e. clean code, ease of maintenance) just to blindly adhere to the "best practices". You're exchanging one evil for a far bigger one :)

That said, I look forward to you cleaning up and decoupling the controller code, and then, I will be glad to learn about and adopt your approach, because I would also like to, ideally, follow the MacOS best practices. I'm just not willing to do it at the expense of code cleanliness.

Hope I made some sense.

----------------------------

Side note:

Another thing - I always ask myself, "What is the ultimate mission of this project ?". For me, it's 3 things, listed in descending order by importance:
1 - To have fun (most important)
2 - To have a simple music player for my daily needs
3 - Ein bisschen Swift lernen (least important) ... not all of it ... just enough to satisfy priorities 1 and 2

Note that "Pleasing the Apple developer community" is not listed as a priority, because, well, it isn't a priority :) What I'm trying to say is ... I don't care whether or not my code follows Apple's best practices. What I do care about ... a LOT ... is ... am I having fun working on this project ? I'm not trying to learn everything there is to know about Swift. I don't need this knowledge for work, and I don't need it for anything else ... other than to achieve priorities 1 and 2 :)

I'm mentioning this so you understand my mindset when working on this project, and perhaps understand my decisions. Your goals are distinctly different from mine. You are trying to learn the universe of Swift/MacOS programming. I'm not :) You want to know 15 different ways of docking windows together. For me, one or two ways will do :) You're blazing ahead at breakneck pace on the cutting edge of Swift language versions and best practices. Ich trinke etwas Wein, laughing at silly jokes, and doing a bit of casual Swift 3 programming, applying whatever I've learned thus far, on a 2009 Macbook Pro which will keep me blissfully happy until I die or it dies (whichever comes first) :p

(Always keeping priorities 1 and 2 in mind)
 
Last edited:
  • Like
Reactions: Tobias_Dunkel
P.S. I'm working on getting Aural to recognize and respond to trackpad gestures, and it seems like a fun exercise !

Two fingers up/down (player): Increase/decrease volume, like VLC
Two fingers left/right (player): Seek forward/backward, like VLC
Three fingers left/right (player): Previous/next track, like Firefox's back/forward
Three fingers up/down (playlist): Scroll to top/bottom of playlist, like Firefox

Thoughts ?
 
  • Like
Reactions: Tobias_Dunkel
The option to only load the animations while the window is visible/open would be a good compromise and if it can be done without a huge amount of work I am totally in for it.

:)

CPU.gif


CPU2.gif
 
  • Like
Reactions: Tobias_Dunkel
Wow that's very impressive :D I would say this way you get the best of both worlds (thumbs-up)
[doublepost=1510235618][/doublepost]
Ok, so breaking your response into multiple quotes is a larger endeavor than I can manage right now, so I will respond to it in one big chunk.

Yes, I totally get your trying to get a working start ... that is how I begin any project too, and I code iteratively too. That's fine, I get it.

To answer your question about why the seek slider and certain menu items are referenced in the PlaybackViewController, you might recall me mentioning a while ago that my view controllers each handle either one "logical component" (or "aspect") of the app, or a physical one (i.e. a view). Playback is one aspect of the app, so I wanted all playback functions to be handled by PlaybackViewController. The alternative would be to put those items in controllers each responsible for one view, but send out messages to initiate playback. The irony is that, no matter which way it is done, separation of concerns is both 1 - somewhat created, and 2 - somewhat violated. I chose one way of doing it. So, whether it's a menu item, button, playlist table view, or the kitchen sink, ... if it triggers playback, it's in PlaybackViewController. That was my reasoning. Now, this may not be the MacOS/Swift way of doing things, but it makes sense to me.

So, if, at any time, you're unsure where to look for code handling a certain UI element, ask yourself, "Which aspect of the app is this control responsible for ? Playback ? Playlist CRUD ? Effects ?". That will point you to which ViewController class(es) the control will be referenced in. Example - you wanna know where the seek slider action function is ... "What happens when I move the seek slider ? The player seeks forward/backward. What aspect of the app is this ? Playback ! Let's look in PlaybackViewController. But, also, another aspect - "Now Playing Info". The seek slider's position has to be updated as playback proceeds. Which controller shows Now Playing info ? NowPlayingInfoViewController."

I am certain of two things:

1 - You have done way more research and know way more about the MacOS best practices/guidelines than I do. No question about it.
2 - There are a lot of MacOS guidelines that I am not following, partly because I'm not even aware of them.

Admittedly, I'm going about this whole project with pretty much the same approach I'd apply to a Core Java back end web service project, and that is reflected in the code I write. And, often, it directly conflicts with the MacOS way of doing things. But, there is also a lot of wisdom in that approach, because it is based in a bedrock of solid coding/design principles, and so, I don't see it as being an invalid approach, just different. MacOS best practices or Apple may not agree with it, but ... I won't lose any sleep over it. There are certain coding/design fundamentals that apply to any project, regardless of whether its a server-side Java app or a user-facing Swift app.

What I was trying to say was that I agree that the XIB should be split up ... no doubt ! And, I'm well aware of the benefits of doing so. Apart from maintainability, there is the huge advantage of a faster app startup and possibly also a smaller memory footprint ? (don't need to load preferences/sort/search dialogs ... they can be in separate XIBs and loaded lazily)

However, where I stop agreeing with that paradigm is where I see XIB instantiation code spread all over the place and one window controller accessing "private" members from another controller. I absolutely agree with what you're proposing. I'm just not agreeing with how.

The way IINA has done it (which you followed) flies in the face of tried and true OOP and general design principles I've been applying my whole career. If I have to completely abandon code cleanliness to achieve the separate XIBs, then I will steadfastly refuse to do so. In other words, any advantage gained by breaking up the big XIB is entirely lost if the code becomes as ugly as what I saw. You're completely defeating the purpose of breaking up the XIBs (i.e. clean code, ease of maintenance) just to blindly adhere to the "best practices". You're exchanging one evil for a far bigger one :)

That said, I look forward to you cleaning up and decoupling the controller code, and then, I will be glad to learn about and adopt your approach, because I would also like to, ideally, follow the MacOS best practices. I'm just not willing to do it at the expense of code cleanliness.

Hope I made some sense.

----------------------------

Side note:

Another thing - I always ask myself, "What is the ultimate mission of this project ?". For me, it's 3 things, listed in descending order by importance:
1 - To have fun (most important)
2 - To have a simple music player for my daily needs
3 - Ein bisschen Swift lernen (least important) ... not all of it ... just enough to satisfy priorities 1 and 2

Note that "Pleasing the Apple developer community" is not listed as a priority, because, well, it isn't a priority :) What I'm trying to say is ... I don't care whether or not my code follows Apple's best practices. What I do care about ... a LOT ... is ... am I having fun working on this project ? I'm not trying to learn everything there is to know about Swift. I don't need this knowledge for work, and I don't need it for anything else ... other than to achieve priorities 1 and 2 :)

I'm mentioning this so you understand my mindset when working on this project, and perhaps understand my decisions. Your goals are distinctly different from mine. You are trying to learn the universe of Swift/MacOS programming. I'm not :) You want to know 15 different ways of docking windows together. For me, one or two ways will do :) You're blazing ahead at breakneck pace on the cutting edge of Swift language versions and best practices. Ich trinke etwas Wein, laughing at silly jokes, and doing a bit of casual Swift 3 programming, applying whatever I've learned thus far, on a 2009 Macbook Pro which will keep me blissfully happy until I die or it dies (whichever comes first) :p

(Always keeping priorities 1 and 2 in mind)

Great response, this clears up some stuff for sure, and now I'm understanding all the logic behind the structuring you did. Also you're right, that my priorities may look different. Since I'm doing this to learn macOS development, but with that prpoject I can do it in a fun and interesting way that keeps me motivated. So having fun is also a motivation of mine but probably only comes 2nd, after improving my coding abilities.

Since I don't have that programming background you have, of course, the only way of doing things I know of is the apple way. So, when I see someone doing it different, of course this confuses me. So I will try to stick with the apple path on my branch, so I can use all those tutorials and all the sample code from apple as a guide for my development.

Regarding point two: When I discovered Aural it already fulfilled my daily needs for listening to music, to be true.
This means, for me, it's more about improvement, testing things out, learn coding and..having fun :)

Right now I'm doing some sample projects to learn all about dependency injection and the different ways to achieve it. So, won't be doing work on Aural itself for a few days.
[doublepost=1510235901][/doublepost]
P.S. I'm working on getting Aural to recognize and respond to trackpad gestures, and it seems like a fun exercise !

Two fingers up/down (player): Increase/decrease volume, like VLC
Two fingers left/right (player): Seek forward/backward, like VLC
Three fingers left/right (player): Previous/next track, like Firefox's back/forward
Three fingers up/down (playlist): Scroll to top/bottom of playlist, like Firefox

Thoughts ?

Will do a detailed response about that, where I'll explain my thoughts on it.
For now I'm only agreeing on the seek gesture. This would indeed be a cool feature to have.
 
  • Like
Reactions: 0002378
Wow that's very impressive :D I would say this way you get the best of both worlds (thumbs-up)
[doublepost=1510235618][/doublepost]

Great response, this clears up some stuff for sure, and now I'm understanding all the logic behind the structuring you did. Also you're right, that my priorities may look different. Since I'm doing this to learn macOS development, but with that prpoject I can do it in a fun and interesting way that keeps me motivated. So having fun is also a motivation of mine but probably only comes 2nd, after improving my coding abilities.

Since I don't have that programming background you have, of course, the only way of doing things I know of is the apple way. So, when I see someone doing it different, of course this confuses me. So I will try to stick with the apple path on my branch, so I can use all those tutorials and all the sample code from apple as a guide for my development.

Regarding point two: When I discovered Aural it already fulfilled my daily needs for listening to music, to be true.
This means, for me, it's more about improvement, testing things out, learn coding and..having fun :)

Right now I'm doing some sample projects to learn all about dependency injection and the different ways to achieve it. So, won't be doing work on Aural itself for a few days.
[doublepost=1510235901][/doublepost]

Will do a detailed response about that, where I'll explain my thoughts on it.
For now I'm only agreeing on the seek gesture. This would indeed be a cool feature to have.

Of course, you should do things in whatever way makes sense to you. That is another reason I insisted on us keeping separate code bases :) I'm sure you're thanking your stars for that now ! I knew that we would run into the problem of "too many cooks in the kitchen", which is a common occurrence in the programming world. Programmers have their own ways of doing things, and unless there is a governing agency (like an architect from Norway) that lays down the rules, the collaboration can become very challenging and almost deadlocked. I surely didn't want that for me in this project, and you don't want that either ... you don't want me and my old school ways getting in the way of your learning :)

"Dependency injection" caught my attention because it is almost a complete summary and selling point of the Spring Java framework I used (and loved) for years. If you could share a summary of what you learned, once you're done with the learning, I'd be interested in hearing it.

BTW, you might also like hearing that last night, I moved the 3 modal dialogs (prefs, search, sort) into their own XIBs ... this is fully working. I'm currently in the process of moving Playlist into its own XIB ... it's about 75% done. And, the code is pretty clean so far ... menu controllers (like in your codebase), window controllers, a Window "factory" that instantiates my XIBs, and the modal dialogs are exposed through protocols so that the classes using them can only access a bare minimum of functionality on those window controllers.

:)
 
BTW, you might also like hearing that last night, I moved the 3 modal dialogs (prefs, search, sort) into their own XIBs ... this is fully working. I'm currently in the process of moving Playlist into its own XIB ... it's about 75% done. And, the code is pretty clean so far ... menu controllers (like in your codebase), window controllers, a Window "factory" that instantiates my XIBs, and the modal dialogs are exposed through protocols so that the classes using them can only access a bare minimum of functionality on those window controllers.

:)

UPDATE: There are now 7 XIB files in my Aural codebase :D

The code is clean and everything works beautifully, except for one pesky bug related to the initial positioning of the playlist window.

I'm glad you pushed me to break apart the big XIB :D

Also, thanks to you, I discovered NSWindow.setFrameTopLeftPoint (never knew such a function existed !).
 
  • Like
Reactions: Tobias_Dunkel
UPDATE: There are now 7 XIB files in my Aural codebase :D

The code is clean and everything works beautifully, except for one pesky bug related to the initial positioning of the playlist window.

I'm glad you pushed me to break apart the big XIB :D

Also, thanks to you, I discovered NSWindow.setFrameTopLeftPoint (never knew such a function existed !).

I'm glad you're breaking stuff apart as well. Will make things more structured and future proof for sure. When I finished my research about DI and decoupling, of course, I can report about that if you like so :)

What doesn't work with the initial positioning?
For example, I did initial positioning for both windows with .windowController?.windowFrameAutosaveName which makes a window remember it's last position (setting an autosave name in IB isn't enough). Additionaly I store the playlist dock state in the UserDefaults which can be restored on reopening the app. Works fine every time. Maybe this helps, but after all I don't know what bug/problem you're facing.
 
What doesn't work with the initial positioning?
For example, I did initial positioning for both windows with .windowController?.windowFrameAutosaveName which makes a window remember it's last position (setting an autosave name in IB isn't enough). Additionaly I store the playlist dock state in the UserDefaults which can be restored on reopening the app. Works fine every time. Maybe this helps, but after all I don't know what bug/problem you're facing.

Yes, I'd like a report. I fixed the window positioning. Dunno what the problem was but I've rewritten a lot of the docking code, inspired by some of your docking code.

Here's the new history/favorites feature I'm adding ...

Favs.gif


History.png
 
Last edited:
  • Like
Reactions: Tobias_Dunkel
Wow, how could you add those features that quick?
Is this working already, or is it just a mockup?

Side note: Since the 'now playing' section is slightly bigger now in terms of height, not sure if it would make sense to increase the size of the album cover as well to have the same gap on the top, left and bottom between it and its parent view.
 
Wow, how could you add those features that quick?
Is this working already, or is it just a mockup?

It's working :) I just need to clean up the code and do thorough testing. It was not that complicated, and I learned how to write an LRU data structure using generics in Swift. I loved generics in Java and Swift's generics is not that different.

Side note: Since the 'now playing' section is slightly bigger now in terms of height, not sure if it would make sense to increase the size of the album cover as well to have the same gap on the top, left and bottom between it and its parent view.

Yes, I thought of that when enlarging the Now Playing box. However, only the height available to the art view increased, not the width (the width increase was given entirely to the artist/title display, and for good reason). So, to keep the art view square, it cannot be changed in any way. It wouldn't make sense to have it be rectangular. And, if we increase its width to keep it square, the whole window will have to be wider as well.
 
Adding some keyboard shortcuts for convenient access to frequently used controls:
- increasing/decreasing all bass (or mid or treble) EQ bands
- increasing/decreasing pitch shift
- increasing/decreasing playback rate

What do you think would be intuitive shortcuts for the above operations ? I was thinking Shift B and Option B for increase/decrease bass, for example.

Bass.gif
 
Adding some keyboard shortcuts for convenient access to frequently used controls:
- increasing/decreasing all bass (or mid or treble) EQ bands
- increasing/decreasing pitch shift
- increasing/decreasing playback rate

What do you think would be intuitive shortcuts for the above operations ? I was thinking Shift B and Option B for increase/decrease bass, for example.

View attachment 735031

I'm not really a shortcut guy (use them very rarely), but in general it's not a bad idea to have shortcuts for people who use them. Having too many shortcuts on the other hand are hard to remember and may conflict with other software, so having them configurable would be a good choice in that case.

1)
What I would propose however, at least for the equalizer, would be three selector buttons (next to the bands) for the band regions (like "L", "M", "H" respectively for low, mid and high).
These buttons select all the corresponding sliders at once.
The values can then be changed with the up and down arrows or a different shortcut increasing and decreasing.

2)
An alternative would be a HUD overview (shown by pressing a shortcut) listing all the parameters (EQ low, EQ mid, ..., Pitch) which can then be:
- selected with the up and down arrows (like you currently select a track in the playlist with up and down)
- changed with left and right arrows
- reset to default with backspace
The HUD window would be closed by pressing enter.
So this window would kind of act like a 'control center' for frequently changed parameters.

Though both of my proposals would be a lot more work to implement than just having a lot of separate shortcuts.
 
Last edited:
  • Like
Reactions: 0002378
I'm not really a shortcut guy (use them very rarely), but in general it's not a bad idea to have shortcuts for people who use them. Having too many shortcuts on the other hand are hard to remember and may conflict with other software, so having them configurable would be a good choice in that case.

1)
What I would propose however, at least for the equalizer, would be three selector buttons (next to the bands) for the band regions (like "L", "M", "H" respectively for low, mid and high).
These buttons select all the corresponding sliders at once.
The values can then be changed with the up and down arrows or a different shortcut increasing and decreasing.

2)
An alternative would be a HUD overview (shown by pressing a shortcut) listing all the parameters (EQ low, EQ mid, ..., Pitch) which can then be:
- selected with the up and down arrows (like you currently select a track in the playlist with up and down)
- changed with left and right arrows
- reset to default with backspace
The HUD window would be closed by pressing enter.
So this window would kind of act like a 'control center' for frequently changed parameters.

Though both of my proposals would be a lot more work to implement than just having a lot of separate shortcuts.

.. And I forgot to mention. New keyboard shortcuts implies new menu items, because I'm using menu items' key equivalents to get the keyboard shortcuts for free :D Keyboard shortcuts are, in fact, a key feature of the app, because that is precisely what I loved about Winamp ... with 3 key presses, I had my favorite tune playing, without so much as looking at the mouse.

soundMenu.png


Believe it or not, I was very strongly considering option 1 before I even thought of keyboard shortcuts. I held off on implementing it because I thought the EQ UI might look too cluttered with the additional buttons. But, maybe I will give it a go and see what it looks like. I also like the idea of making the shortcuts configurable, but that will be a bit involved because I have to detect conflicts n stuff like that. But, it might be ideal because user preferences vary.

Option 2, in my opinion, would be a bit redundant because the FX panel is already right in front of the user and has all the controls. So, if the user is going to bother bringing up a HUD panel, he might as well just switch to the Pitch (or other) tab and do whatever.

The keyboard shortcuts are great because they achieve whatever you want with one single action. If more than one action is required, then the user might as well use the FX panel itself (because he can switch tabs with one click). Just my opinion.

Thanks for the feedback. BTW, I've been meaning to tell you - I tried out your window transparency demo app a while ago. It looked good. But, I'm a little confused - what would be the advantages of that over having multiple windows ?

P.S. - Now that I'm addicted to having multiple XIBs, I'm thinking of even separating different views (container boxes) on the main window, into their own XIBs (i.e. Now Playing box, Player Controls box, FX box), and perhaps even the individual FX tabs into their own XIBs with one master tab controller and individual FX controllers. I remember you mentioning it in an older post ... that a window can simply have placeholders and import views from other XIBs :D

[doublepost=1510610546][/doublepost]BTW, my new window docking approach was also inspired by yours ... it ensures that the entire playlist window is visible at all times. And, I've updated the dock/maximize icons to have rounded corners because of the rounded window corners.

Docking.gif
 
Last edited:
  • Like
Reactions: Tobias_Dunkel
Option 2, in my opinion, would be a bit redundant because the FX panel is already right in front of the user and has all the controls. So, if the user is going to bother bringing up a HUD panel, he might as well just switch to the Pitch (or other) tab and do whatever.

The keyboard shortcuts are great because they achieve whatever you want with one single action. If more than one action is required, then the user might as well use the FX panel itself (because he can switch tabs with one click). Just my opinion.

I do not agree on that. You could only have a single panel open or even none. Plus, even when it's open you need to use to mouse to actually change values. Like I said, I'm not a hardcore shortcut user, so maybe i get the intention wrong, but I see keyboard shortcuts as a way not having to use the trackpad or a mouse.

Plus you probably want to use the shortcuts without the main window even being visible.
Example:
- You browse the web, listen to some music in the background.
- The next song comes up and you wanna boost the bass since you feel that song could need some more low end.
- You press a shortcut (e.g. Alt-Shift-P) and an overlay pops up
- There you have a numbered list of actions you can do like: "1. EQ low"
- so you either press "1" or up/down to navigate to that option
- now with left/right you increase/decrease the low end

Since all those keys are really next to each other it probably doesn't take that much longer than a single shortcut which you have to remember for every action you do. Here you have to know a single shortcut.

Plus, I think those are actions that you don't need all the time like: 'next song' or 'seek forward'. So it doesn't matter that much if it takes half a second or maybe a second longer. And you don't have to switch focus from browsing the web to actually make that adjustment since you don't have to switch window. Additionally the shortcuts are way more unlikely to conflic with the browser you're working in.

Another somewhat related example:
- I want to open a specific app on my macbook (it may or may not be accessible directly in the dock)
- Most of the time i just press 'cmd + space', type the name and press enter
- doing this I'm most of the time even quicker then going with the mouse to the dock and clicking the icon
- with the HUD overlay I had in mind, it would be somewhat the same
- like: 'Alt-Shift-P' + '4' + 'left' + 'enter' would raise the pitch by a defined increment (in case 4 is the number for the pitch control) and it would take me about 1 1/2 seconds for the whole action without shifting focus to the player.

In my opinion, this would be the best way to handle this instead of many separate shortcuts, but like I said this would be very involved.

Thanks for the feedback. BTW, I've been meaning to tell you - I tried out your window transparency demo app a while ago. It looked good. But, I'm a little confused - what would be the advantages of that over having multiple windows ?

First the overall window behavior is somewhat different. Second you wouldn't need any of the docking logic in the app. You could deleta all that 'window management' code. But since everything works fine as well like it is at the moment, it's probably better to stay with it. In the end it was just a UX experiment I did.

P.S. - Now that I'm addicted to having multiple XIBs, I'm thinking of even separating different views (container boxes) on the main window, into their own XIBs (i.e. Now Playing box, Player Controls box, FX box), and perhaps even the individual FX tabs into their own XIBs with one master tab controller and individual FX controllers. I remember you mentioning it in an older post ... that a window can simply have placeholders and import views from other XIBs :D
[/QUOTE]

That's exactly where I'm going after, but first I wanted to have full DI before I spread it apart any further.

Maybe even going as far as creatin the tab view controller for the effects programmatically, then simply add all the neccessary views to it in code. Would probably make it a one-liner in code to add an addtional effect in the future.

The main window also could just be an empty stack view controller set up programmatically and then all the views could just be added to it with an array of views (nowPlaying, playerControls, etc.) and a loop to add each one.

Somehow I'm more and more getting drawn to do stuff in code rather than IB, since code is easier to handle and change.
 
  • Like
Reactions: 0002378
Cool. Ok, I need to think a bit about the HUD panel and stuff. Will keep it in mind. Thanks for the detailed feedback.

As you read about DI, also look at messaging models (because they are a crucial part of decoupling).

Looking forward to creating that new Swift 4 mother-of-all-branches branch soon, with merged changes :D
 
[doublepost=1510610546][/doublepost]BTW, my new window docking approach was also inspired by yours ... it ensures that the entire playlist window is visible at all times. And, I've updated the dock/maximize icons to have rounded corners because of the rounded window corners.

Glad you like my approach
Doing it that way was just a means to an end. Since I used a regular window for the playlist I got some unwanted behavior when part of the window moved off screen. Didn't knew it behaved differently to a borderless window until you taught me. So that's why I initially implemented that behavior, not because I wanted it to be that way. But in the end I also prefered it
[doublepost=1510617566][/doublepost]
Cool. Ok, I need to think a bit about the HUD panel and stuff. Will keep it in mind. Thanks for the detailed feedback.

As you read about DI, also look at messaging models (because they are a crucial part of decoupling).

Looking forward to creating that new Swift 4 mother-of-all-branches branch soon, with merged changes :D

Thanks for the advice.
How I understand it, sending messages and data between different parts of the app is what DI/decoupling mostly is about.

I actually have a question related to that:
Can you recommend any book about programming architecture?
Few days ago I watched a video from Robert C Martin about 'clean architecture' on Youtube and he totally impressed me.
I'll probably buy his book about clean architecture, but first i wanted to ask you if you could recommend a different book about app architecture, which may be even better?
 
Didn't knew it behaved differently to a borderless window until you taught me.

Yeah, I noticed that my up/down arrows weren't sending key events to the playlist for normal/natural scrolling. Did a lot of research and finally discovered that when there is no title, key events are not sent to the NSTableView. However, what I love about title-less windows is that no window can hog the focus of the app (at least it seems that way). So, my playlist is always in focus, and that's how I want it to be. All I had to do, because key events weren't being sent, was to write a few lines of code to invoke playlistView.keyDown(event).

Thanks for the advice.
How I understand it, sending messages and data between different parts of the app is what DI/decoupling mostly is about.

Yes, but DI, by itself, refers only to injecting dependencies into objects upon startup, and how that is achieved. Messaging is separate from that. And yes, DI + Messaging = Decoupling.

The reason I like having objects declared in the XIBs is because it is very similar to how you declare objects with Spring (Java). You put them either in an XML file or a separate Java class that does nothing but initialization. That way, your app code doesn't get contaminated with DI code.

Now, I've split up the XIBs but that doesn't mean I'm putting XIB instantiation code everywhere. It is neatly abstracted away in one "factory" class that does nothing but instantiate XIBs and give you WindowControllers and ViewControllers, but it does so, again, with abstraction in mind. Exposes them through protocols. You NEVER get a WindowController instance or ViewController instance. You get something like ModalDialogDelegate which exposes one or two methods.

I actually have a question related to that:
Can you recommend any book about programming architecture?
Few days ago I watched a video from Robert C Martin about 'clean architecture' on Youtube and he totally impressed me.
I'll probably buy his book about clean architecture, but first i wanted to ask you if you could recommend a different book about app architecture, which may be even better?

Wow, good question ! I'm stumped, because I never read any specific architecture books ... I read a lot of Java books, but never architecture books. I just picked up bits and pieces of architecture design by working on many projects and from discussions with architects. So, my knowledge is from all over the place ... it didn't come from one specific source that I can recommend.

For instance, let's say my new project at work requires "Publish/Subscribe messaging". I'll just Google that and read a few articles on it. Or, when the architects at work call for a design review meeting, they'll whiteboard it and I'll pick things up from there.

Sorry, I don't have any specific books to recommend. But, I can certainly recommend topics that you might wanna read up on ... keywords that could bring up useful info. I'm having lunch ATM but lemme get back to you with that list.
[doublepost=1510621219][/doublepost]So, I have no idea what you already know. Also, I don't know what your ultimate goal is ... i.e. which direction you want to head in. I'm sure you know that you don't know and I don't know how vast the subject of Computer Science and its applications is :) I'm going to recommend stuff from the ground up. These are keywords that you can look up and read up on.

Object Oriented Programming fundamentals - I cannot overemphasize the importance of this. Concepts like Abstraction and Encapsulation are key principles that will even come in handy when thinking about architecture. Abstraction on a small scale can refer to hiding variables in a class, while on a larger scale (architecture) can refer to how app components or even separate apps talk to each other without knowing each others' implementation details.

Concurrency and thread pooling - Concurrency is a must-know in almost any modern app. Thread pooling refers to an efficient use of a "pool" of threads to execute tasks simultaneously. It is not relevant anymore in MacOS/AppKit programming because there is now GCD, which mean you don't have to know how to create threads/pools, and you work directly with queues. But, learning about the concepts can't hurt.

Design Patterns - These are just recipes for solving commonly faced problems, and are great to know. Again, they can be applied on both a micro scale (variables/objects), or a macro scale (app components / apps). Examples - Singleton, Facade, Factory, MVC, Observer, etc ...

https://en.wikipedia.org/wiki/Software_design_pattern

Messaging - I've mentioned it a few times already, but I'm a big fan of the Publish/Subscribe messaging model, and have used it quite a bit.

https://en.wikipedia.org/wiki/Publish–subscribe_pattern

N-tiered software architecture - Traditional client-server architecture. Again, conceptually, this can be applied on a small/large scale. I used it in Aural Player ... with my 3 app layers (View, Delegate, Back end) Aural is actually closer to 3-tier architecture than to MVC. Layers and tiers are different things, but conceptually, the same.

https://en.wikipedia.org/wiki/Multitier_architecture

Service Oriented Architecture - My previous job was all about SOA. This is how most scalable web apps are implemented these days. I learned a great deal from SOA !

https://en.wikipedia.org/wiki/Service-oriented_architecture

OSI model (networking) - Defines/describes different levels of abstraction in any kind of network communication. For instance, if you know about HTTP, the OSI model gives you the big picture of where HTTP fits into the grand scheme of things. Very good to know about.

I've applied most of the above concepts in one shape or form, in this project.
 
Last edited:
  • Like
Reactions: Tobias_Dunkel
I wanted to share just a few general programming tips/ideas, from whatever I've learned and experienced.

Coding iteratively: There are so many aspects to software development, that it is not possible to attack all of them in one go, so code must be written iteratively, and I have done so from the very beginning. My process usually looks something like this (and not always in this order):

- Get it working for the simplest possible use case, one way or another, no matter how ugly, inefficient or redundant. This is to prove that the attempted goal is feasible in the first place ... some may not be. A "proof of concept".

- Reliability: Think about the less likely cases (e.g. invalid user input), and edge/corner cases (i.e. unlikely but possible cases) ... for instance, the user doing something totally weird with the app.

- Efficiency/performance: analyze loops, method calls, look at how much memory is being allocated (data structures). Are your data structures best suited for the purpose ? Are you doing real-time data lookups for the user ? Think about O(1) performance for lookups if possible. Are you doing background tasks ? Data structures have tradeoffs ... Swift Dictionary objects, for instance, give you O(1) average lookup time, but cannot and will not guarantee iteration order when you later want to read all the objects in them. WTF !!! So, tradeoffs ... Do you need object uniqueness (no duplicates) ? Set.

- Thread-safety: How many, and which, threads will access this piece of code ? Am I modifying any shared data here ? If so, are my data structures thread-safe ?

- Reduce redundancy ... see if the code can be factored out into a private helper or public util. Or, look for a 3rd party library that does part or all of what you just wrote.

- Extensibility: If I were to augment this feature in the future, would it be easy ?

- Readability and code commenting: Comment, at least, the parts that are not obvious to the reader (like any complex algorithm steps or obscure programming tricks). You'll thank yourself a month later, when you revisit the code. Each class and each public method/function should have at least a one-liner explaining its purpose. Whenever assumptions are made (e.g. a function parameter must be a non-nil positive integer between 1 and 10), document those assumptions in the code. Otherwise, no one (not even you) will remember them months later.

- Documentation: Provide your end users/clients with the basic knowledge of how to access the public interface of whatever code you write. This could be an entire app/service or just one class. The client could be a customer or the dude in the cubicle next to yours who is going to write a layer on top of your code. Make the public interface well-defined and unambiguous. Again, document all assumptions.

- Security/scalability: This doesn't necessarily apply to all apps, but let's say you're working on a commercial web app that serves tens of thousands of global users. Security is self-explanatory, and scalability then becomes a key part of your programming process. Each choice of data structure or control structure can make a difference. Load testing (another good thing to look up) is making sure that your production system has the performance and resources to serve its current user base + a safety margin for growth.

- 3rd party code: Has this logic I'm writing been implemented by others and well-tested before ? i.e. in a 3rd party library ? For instance, in the Java world, the Apache project (and later Google code) was the go-to for open source libraries for doing anything and everything in Java. Are there any known issues with this library that will introduce bugs into my app ?

- Testing: There's unit testing, integration testing, manual testing, load testing. Figure out what kinds are needed for your app. In the real world, you will likely use all 4 (and more). Load testing is particularly interesting and I was heavily involved in it.

Tradeoffs: The occupation of software development, like civil engineering or almost any other field, is largely about tradeoffs or compromises. Whenever you make a decision, you will likely achieve certain advantages while sacrificing others. Always keep this in mind. Examples follow:

- Code readability vs conciseness/efficiency: I've come across this tradeoff almost on a daily basis when developing. This is best explained with an example.

Code:
// One way of doing it

let randomIndex: Int = random(userPrefs.minInt, userPrefs.maxInt)
let randomTrack = playlist.getTrack(randomIndex)
player.play(randomTrack)

// Another way

player.play(playlist.getTrack(random(userPrefs.minInt, userPrefs.maxInt)))

This is an exaggerated case, but sometimes, readability is more important than conciseness, esp. when working in a team environment where others will look at your code.

The language you're using, and Swift is a great example, may provide a lot of syntactic sugar to help you code concisely, which is great, and you will be tempted to reduce your code to one liners, but don't ignore readability completely.

If you choose conciseness over readability, code commenting becomes all the more important.

- Sweeping the dirt under the rug: Sometimes, you will rush to refactor one piece of code you deem ugly, and not realize that by cleaning one piece of code, you have created another piece of code that is 10 times uglier. I encountered this with what I saw in the IINA code with WindowControllers all over the place. In order to blindly adhere to "best practices", there are 10 short and sweet XIBs, but parts of the source code are ugly and violate fundamental OOP principles. The dirt has been swept under the rug :) It didn't disappear; it just moved from one place to another, and somehow even managed to grow ;)

- Sacrificing performance (sometimes) for a better user experience: This seems like a contradiction. Usually, user experience is directly tied to better performance, but how can you forget the example of the GIF animations you despise so much :)

Now, of course, it is important to note that a GIF animation causes a CPU spike; simply ignoring it would not be prudent. But, when it comes to making a decision of whether or not to allow it at all, you have to step out of the shoes of the programmer and put yourself in the shoes of the users. Some users would prefer that it be totally disabled, because it gets annoying and/or CPU performance. Other users (e.g. iMac Pro users with 32 cores) may like the visuals and prefer it be on all the time. If you assume one way or the other, you're making the decision as a programmer, not as a user. "This takes up a lot of CPU so let's put a boring little text symbol there and do away with it." - this is merely a programmer's perspective, because we know that CPU time should not be wasted. Zoom out and look at the bigger picture. What would your users want ? Improved CPU usage, longer battery life, and also a nice animation when they're in the mood ! Base your decisions on that.

Of course, this is why any software development shop of reasonable size has a UX department :D

- Time vs the "best" solution: Playing with sample XCode projects from Ray Wenderlich and finding 15 ways to dock two windows is a lot of fun and when learning, time is no object. But, in the real world, time is a very real thing, and often times, you will be forced to implement a solution that you're not the biggest fan of, and move on to the next task. You'll need to pick a candy bar and rush back to the train because the train is about to depart on its way to the next station. And that is ok, if you can find a balance/compromise that works.

In the real world, there is a time and place for research and learning, and there is a time and place for getting things done. The dudes with the PhDs are usually the ones in R&D exploring 100 different protocols for inter-process communication. Head over to the Engineering building across the campus and you'll see developers building and deploying releases to a production environment and responding to bug reports. I was in the Engineering building, of course :)

Both are great to have, and there needs to be a balance between the two. R&D provides valuable input to Engg on how something can be done best, and Engg gets it implemented and shipped. Too much R&D and you get nowhere in the end. No learning and you ship solutions that suck.

Over-engineering is a common problem among developers arguing over for loops. Not every app is a NASA rocket saving the Earth from an asteroid, and not every for loop deserves an hour of debate, so learn to manage time and give every problem its due time and attention. This may not make any sense to you right now, because you're in the "lab" and everything seems important, and you don't have to worry about deadlines, but get out in the real world and you'll see what I mean.

In any case, balance is always a good thing to have. You can spend a week on figuring out the "best" window docking solution, or you can spend 2 days on it, and get 5 other features implemented :)

- Zoom out: Being too "zoomed in" is another common problem among developers. They get too focused on their tiny problem that they lose sight of the bigger picture/context. This is with anything in life, really. It helps to step back and see the bigger picture of what you're trying to achieve and how. Things become clearer then.

And, with so many different ways of doing something, esp. with programming, it can be confusing to have to pick one way of doing things. It always helps to "zoom out" from your little class or module to the app or project as a whole, and ask yourself what the ultimate goal(s) are. Who are my end users ? What do they want from this app ? Is this a standalone desktop app or is it simultaneously serving a million online global users ?

When stuck on a problem, don't always insist on jumping over the hurdle. Sometimes, it is best to walk around the hurdle.

Yes, we need guidelines and best practices for structure, but don't let them constrain you into blindly adhering to them. Apply them in a larger context. First of all, realize that there IS a larger context. Then, apply those details within it. Don't confuse personal preferences or even "best practices" with what is "best". Often, what is "best" has a lot more to do with the clients and how they will use the app, than with the programmers. And sometimes, the "best" solution is simply the one that makes it to the customer on time :D

Hope this helps.
 
Last edited:
  • Like
Reactions: Tobias_Dunkel
UPDATE: Implemented gesture recognition ! It was actually quite easy once I figured out which event types match which gestures. They work beautifully.

Playlist gestures:
Three finger swipe up/down - Scroll to top/bottom
Three finger swipe left/right - Switch playlist view tabs (Tracks/Artists, etc)
(Two finger vertical scrolling is enabled by default, and is unchanged)

Player gestures:
Three finger swipe left/right - Previous/Next track
Two finger swipe left/right - Seek backward/forward
Two finger swipe up/down - Increase/decrease volume

Will release an updated build soon.
 
  • Like
Reactions: Tobias_Dunkel
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.