How can I design classes that follow SOLID without off loading violations of SOLID somewhere else? - c++11

I have a controller that is violating Open and Closed Principle. I'm trying to figure out how to solve this with certain conditions. Here is the implementation.
struct BasicRecording
{
void show() {}
void hide() {}
};
struct AdvanceRecording
{
void show() {}
void hide() {}
};
class NotSolidRecordingSettingsController
{
BasicRecording br;
AdvanceRecording ar;
public:
void swithToAR();
void swithToBR();
};
void NotSolidRecordingSettingsController::swithToAR()
{
br.hide();
ar.show();
};
void NotSolidRecordingSettingsController::swithToBR()
{
ar.hide();
br.show();
};
The problem here is if I have a new recording settings, I would need to go back inside settings controller and add that new recording settings. If I inject the BasicRecording and AdvanceRecording in NotSolidRecordingSettingsController, then the Object instantiating NotSolidRecordingSettingsController will need to do the instantiating of BasicRecording and AdvanceRecording. But then that Object then violates OCP. Somebody has to create the object.
How can I design this to be OCP without just off loading the Not OCP part to some other thing?
Is there a particular design pattern for this kind of problem?

In the SOLID principles, OCP is really a consequence of SRP -- a class should have a single responsibility, and its code should only change when its internal requirements -- the requirements associated with its one job -- change.
In particular, a class shouldn't have to change because it's clients change. It may have a lot of clients and you don't want to mess with its code every time it gets new clients or the existing clients need to do something different. Hence OCP. Note that in OCP, "closed for modification" means you don't mess with it when you change the stuff that uses it. You do modify it when its own internal requirements change. That's just maintenance.
So OCP is about how classes relate to their clients, BUT, there are classes that have no clients. Their job is not to be services, and they are not used by other classes or to implement APIs, etc. These classes do not need to worry about OCP, because they naturally have no reason to change other than a change to their internal requirements.
A great example of such a class is what is sometimes called a "composition root" (googlable). Its single responsibility is to define how the system is built from its components. This is the guy that creates all the objects and injects them into everywhere they're needed.
You need a composition root that injects the settings panes into the controller (and whatever triggers them, because you can't have a method called switchToAR anymore). This class' job is to define the system by creating the required objects. When the arrangement of objects needs to change, then, that is a change to its internal requirements and you can go ahead and modify its code without violating SOLID.
(or you can have all that stuff read from configuration instead, but that is just implementing the composition root in config instead of your programming language. Sometimes that is a good idea, and sometimes not)

Related

Handling numerous micro dependencies

I have a service that handles different client types. There are a lot of service classes that differ in minute ways in the way they process different clients. For the most part these classes contain logic that is common to all clients, however there are places with logic specific to clients.
I understand I could use a Factory to return a set of objects for client specific logic, or use the Template method to have concrete implementations of an abstract class for different clients -- the problem with these approaches is that there are a lot of minute branching decisions that have to be made based on the client throughout the code, and these minute branching decisions are trivial, unconnected to each other, and they don't warrant separate classes. Is there a design pattern to elegantly implement this?
class Service {
void process() {
//....
if (client1) doStuff1();
if (client2) doStuff2();
//....
if (client1) name = "xyz";
else if (client2) name = "abc";
//....
if (client1) sortasc();
else sortdesc();
//....
if (client2) processx();
else if (client3) processy();
}
}
It looks like you are falling into a common trap. The service implementation is mostly the same for every, so you want to write the 'common' implementation and then code client-specific extensions. Each time you need to do something special for a client, though, you end up modifying the common service implementation, which quickly becomes an unmaintainable mess.
But really, there is no rule that the implementation has to be the same for every client. If there was such a rule, then you wouldn't have so many exceptions. The truth is that the processing is different for every client, and they just happen to be mostly the same today.
You should make a separate service implementation for each type of client.
If you are now starting to say "but I don't want to duplicate all the common code!", then stop. Take parts that really are common and extract them into utility methods that the different client implementations can call. The amount of code shared is pretty much the same...
class Client1Service implements Service {
void process() {
doCommonSetup();
doStuff1();
doCommonThing();
doStuffWithName("xyz");
sortasc();
doMoreCommonStuff();
processy();
}
}
... but now there's no mess of conditions, and when you need to make client-specific changes, there is a place to do that that doesn't mess up the implementations for all the other clients.
When you need to make changes to the common parts, well, there is also a single implementation of that stuff that you can modify.

C++ RAII, Prototype Design Pattern, and lazy initialization working in tandem

I'm trying my best to adhere to some strict design patterns while developing my current code base, as I am hoping I will be working on it for quite a while to come and I want it to be as flexible and clean as possible. However, in trying to combine all these design patterns to solve the current problem I am facing, I am running into some issues I'm hoping someone can advise me a bit on.
I'm working on some basic homebrewn GUI widgets that are to provide some generic click/drag/duplication behavior. On the surface, the user clicks the widget, then drags it somewhere. Having dragged it far enough, the widget will 'appear' to clone itself and leave the user dragging this new copy.
The Prototype design pattern obviously enters the foray to make this duplication functionality generalizable for many types of widgets. For most objects, the story ends there. The Prototype object is virtually an identical copy of the duplicated version the user ends up dragging.
However, one of the objects I want to duplicate has some fairly big resources attached to it, so I don't want to load them until the user actually decides to click and drag, and subsequently duplicate, that particular object. Enter Lazy initialization. But this presents me with a bit of a conundrum. I cannot just let the prototype object clone itself, as it would need to have the big resources loaded before the user duplicates the dummy prototype version. I'm also not keen on putting some logic into the object which, upon being cloned/duplicated, checks what's going on and decides if it should load in these resources. Instead, a helpful person suggested I create a kind of shell object and when it gets cloned, it were to return this more derived version containing the resources allowing for me to both use RAII and lazy initialization.
But I'm having some trouble implementing this, and I'm starting to wonder if I can even do it the way I'm thinking it should be done. Right now it looks like this:
class widgetSpawner : public widget {
public:
widgetSpawner();
~widgetSpawner();
private:
widget* mPrototypeWidget; // Blueprint with which to spawn new elements
};
class widgetAudioShell : public widget {
public:
widgetAudioShell(std::string pathToAudioFile);
widgetAudioShell( const widgetAudioShell& other );
~widgetAudioShell();
virtual widgetAudio* clone() const { return new widgetAudio(*this); };
private:
std::string mPathToAudioFile;
};
class widgetAudio : public widgetAudioShell {
public:
widgetAudio(AudioEngineAudioTrack &aTrack);
widgetAudio( const widgetAudio& other );
widgetAudio( const widgetAudioShell& other );
~widgetAudio();
virtual widgetAudio* clone() const { return new widgetAudio(*this); };
private:
AudioEngineAudioTrack &mATrack;
};
Obviously, this is not workable as the shell doesn't know the object that's using it to derive a new class. So it cannot return it via the clone function. However, if I keep the two inheritance-wise independent (as in they both inherit from widget), then the compiler complains about lack of co-variance which I think makes sense? Or maybe it's because I am again having the trouble of properly defining one before the other.
Essentially widgetAudioShell needs to know about widgetAudio so it can return a 'new' copy. widgetAudio needs to know about widgetAudioShell so it can read it's member functions when being created/cloned.
If I am not mistaken, this circular dependency is there because of my like of using references rather than pointers, and if I have to use pointers, then suddenly all my other widgets need to do the same which I'd find quite hellish. I'm hoping someone who's had their fingers in something similar might provide some wisdom?

Seemingly redundant event and event handlers

I will explain with an example. My GWT project has a Company module, which lets a user add, edit, delete, select and list companies.
Of these, the add, edit and delete operations lands back the user on the CompanyList page.
Thus, having three different events - CompanyAddedEvent, CompanyUpdatedEvent and CompanyDeletedEvent, and their respective event handlers - seems overkill to me, as there is absolutely not difference in their function.
Is it OK to let a single event manage the three operations?
One alternative I think is to use some event like CompanyListInvokedEvent. However, somewhere I think its not appropriate, is the event actually is not the list being invoked, but a company being added/updated/deleted.
If it had been only a single module, I would have get the task done with three separate events. But other 10 such modules are facing this dilemma. It means 10x3 = 30 event classes along with their 30 respective handlers. The number is large enough for me to reconsider.
What would be a good solution to this?
UPDATE -
#ColinAlworth's answer made me realize that I could easily use Generics instead of my stupid solution. The following code represents an event EntityUpdatedEvent, which would be raised whenever an entity is updated.
Event handler class -
public class EntityUpdatedEvent<T> extends GwtEvent<EntityUpdatedEventHandler<T>>{
private Type<EntityUpdatedEventHandler<T>> type;
private final String statusMessage;
public EntityUpdatedEvent(Type<EntityUpdatedEventHandler<T>> type, String statusMessage) {
this.statusMessage = statusMessage;
this.type = type;
}
public String getStatusMessage() {
return this.statusMessage;
}
#Override
public com.google.gwt.event.shared.GwtEvent.Type<EntityUpdatedEventHandler<T>> getAssociatedType() {
return this.type;
}
#Override
protected void dispatch(EntityUpdatedEventHandler<T> handler) {
handler.onEventRaised(this);
}
}
Event handler interface -
public interface EntityUpdatedEventHandler<T> extends EventHandler {
void onEventRaised(EntityUpdatedEvent<T> event);
}
Adding the handler to event bus -
eventBus.addHandler(CompanyEventHandlerTypes.CompanyUpdated, new EntityUpdatedEventHandler<Company>() {
#Override
public void onEventRaised(EntityUpdatedEvent<Company> event) {
History.newItem(CompanyToken.CompanyList.name());
Presenter presenter = new CompanyListPresenter(serviceBundle, eventBus, new CompanyListView(), event.getStatusMessage());
presenter.go(container);
}
});
Likewise, I have two other Added and Deleted generic events, thus eliminating entire redundancy from my event-related codebase.
Are there any suggestions on this solution?
P.S. > This discussion provides more insight on this problem.
To answer this question, let me first pose another way of thinking about this same kind of problem - instead of events, we'll just use methods.
In my tiered application, two modules communicate via an interface (notice that these methods are all void, so they are rather like events - the caller doesn't expect an answer back):
package com.acme.project;
public interface CompanyServiceInteface {
public void addCompany(CompanyDto company) throws AcmeBusinessLogicException;
public void updateCompany(CompanyDto company) throws AcmeBusinessLogicException;
public void deleteCompany(CompanyDto company) throws AcmeBusinessLogicException;
}
This seems like overkill to me - why not just reduce the size of this API to one method, and add an enum argument to simplify this. This way, when I build an alternative implementation or need to mock this in my unit tests, I just have one method to build instead of three. This gets to be clearly overkill when I make the rest of my application - why not just ObjectServiceInterface.modify(Object someDto, OperationEnum invocation); to work for all 10 modules?
One answer is that you might want want to drastically modify the implementation of one but not the others - now that you've reduced this to just one method, all of this belongs inside that switch case. Another is that once simplified in this way, the inclination often to further simplify - perhaps to combine create and update into just one method. Once this is done, all callsites must make sure to fulfill all possible details of that method's contract instead of just the one specific one.
If the receivers of those events are simple and will remain so, there may be no good reason to not just have a single ModelModifiedEvent that clearly is generic enough for all possible use cases - perhaps just wrapping the ID to request that all client modules refresh their view of that object. If a future use case arises where only one kind of event is important, now the event must change, as must all sites that cause the event to be created so that they properly populate this new field.
Java shops typically don't use Java because it is the prettiest language, or because it is the easiest language to write or find developers for, but because it is relatively easy to maintain and refactor. When designing an API, it is important to consider future needs, but also to think about what it will take to modify the current API - your IDE almost certainly has a shortcut key to find all invocations of a particular method or constructor, allowing you to easily find all places where that is used and update them. So consider what other use cases you expect, and how easily the rest of the codebase can be udpated.
Finally, don't forget about generics - for my example above, I would probably make a DtoServiceInterface to simplify matters, so that I just declare the one interface with three methods, and implement it and refer to it as needed. In the same way, you can make one set of three GwtEvent types (with *Handler interfaces and possibly Has*Handlers as well), but keep them generic for all possible types. Consider com.google.gwt.event.logical.shared.SelectionEvent<T> as an example here - in your case you would probably want to make the model object type a parameter so that handlers can check which type of event they are dealing with (remember that generics are erased in Java), or source from one EventBus for each model type.

Turn-Based-Strategy Game - Where to Store User State

I'm writing a turn-based strategy game. Each player in the game has a team of units which can be individually controlled. On a user's turn, the game currently follows a pretty constant sequence of events:
Select a unit -> Move the selected unit -> Issue a command -> Confirm
I could implement this by creating a game class that keeps track of which of these stages the player is in and providing methods to move from one stage to the next, like this:
interface TeamCommander {
public void select(Coordinate where);
public void move(Coordinate to);
public void sendCommand(String command);
public void execute();
}
However, that would allow the possibility of a method being called at the wrong time (for example, calling move() before calling select()), and I would like to avoid that. So I currently have it implemented statelessly, like this:
interface UnitSelector {
public UnitMover select(Coordinate where);
}
interface UnitMover {
public UnitCommander move(Coordinate to);
}
interface UnitCommander {
public CommandExecutor sendCommand(String command);
}
interface CommandExecutor {
public void execute();
}
However, I'm having difficulty presenting this information to the user. Since this is stateless, the game model does not store any information about what the user is currently doing, and thus the view can't query the model about it. I could store some state in the GUI, but that would be bad form. So, my question is: does anyone have an idea about how to resolve this?
First, there's something I'm not getting here: You have to be storing persistent state somewhere, even if it is only in the View / GUI. Without persistent state you cannot have a game. I'm guessing you're using either ASP or PHP; if so, use sessions to track state.
Secondly, build your state logic into that so it is known where in the input sequence you are for each player / each unit in that player's team. Don't try to get fancy with it. B requires A, C requires B and so on. While you're writing it, just give yourself a scaffold by throwing exceptions if the call order comes up incorrect (which you should be checking on every user input as I assume this is an event driven rather than loop-driven game), and debug it from there.
As an aside: I get suspicious when I see interfaces with a single method as in your second example above. An interface typically informs of there being a unique SET of functionalities which different classes each fulfill -- unless you are trying to construct multiple different classes which use slightly different sets of individual method signatures, don't do what you're doing there. It is all fine and good to say "code to an interface and not an implementation", but you need to first take the top down approach, saying, "How does my ultimate client code (in your root game logic class or method) need to call for such-and-such to occur?" and keep asking that question up the call stack (i.e. at each subsequent sub-call codepoint). If you try to build it from the bottom up, you will end up with the confusing and unnecessarily complicated code I see there. The only other exception to this which I see on a regular basis is the command pattern, and that is generally intended to look like
void execute();
or
void execute(Object data);
...But typically not a whole slew of slightly different method signatures (again possible, but unlikely). My gut feeling comes from my experience with such constructs in that they usually don't make sense and you end up completely refactoring code that uses them.

Loose programming in high level languages, how, why and how much?

I'm writing my code in Haxe. This is quite irrelevant to the question though, as long as you keep in mind that it's a high level language and compareable with Java, ActionScript, JavaScript, C#, etc. (I'm using pseudocode here).
I'm going to work on a big project and am busy preparing now. For this question I'll create a small scenario though: a simple application which has a Main class (this one is executed when the application launches) and a LoginScreen class (this is basically a class that loads a login screen so that the user can login).
Typically I guess this would look like the following:
Main constructor:
loginScreen = new LoginScreen()
loginScreen.load();
LoginScreen load():
niceBackground = loader.loadBitmap("somebg.png");
someButton = new gui.customButton();
someButton.onClick = buttonIsPressed;
LoginScreen buttonIsPressed():
socketConnection = new network.SocketConnection();
socketConnection.connect(host, ip);
socketConnection.write("login#auth#username#password");
socketConnection.onData = gotAuthConfirmation;
LoginScreen gotAuthConfirmation(response):
if response == "success" {
//login success.. continue
}
This simple scenario adds the following dependencies and downsides to our classes:
Main will not load without LoginScreen
LoginScreen will not load without the custom loader class
LoginScreen will not load without our custom button class
LoginScreen will not load without our custom SocketConnection class
SocketConnection (which will have to be accessed by a lot of different classes in the future) has been set inside LoginScreen now, which is actually quite irrelevant from it, apart from the fact that the LoginScreen requires a socket connection for the first time
To solve these problems, I have been suggested to do "Event-Driven-Programming", or loose coupling. As far as I understand, this basically means that one has to make classes independent from each other and then bind them together in separate binders.
So question 1: is my view on it true or false? Does one have to use binders?
I heard Aspect Oriented Programming could help here. Unfortunately Haxe does not support this configuration.
However, I do have access to an event library which basically allows me to create a signaller (public var loginPressedSignaller = new Signaller()), to fire a signaller (loginPressedSignaller.fire()) and to listen to a signalller (someClass.loginPressedSignaller.bind(doSomethingWhenLoginPressed)).
So, with little further investigation I figured this would change my previous setup to:
Main:
public var appLaunchedSignaller = new Signaller();
Main constructor:
appLaunchedSignaller.fire();
LoginScreen:
public var loginPressedSignaller = new Signaller();
LoginScreen load():
niceBackground = !!! Question 2: how do we use Event Driven Programming to load our background here, while not being dependent on the custom loader class !!!
someButton = !!! same as for niceBackground, but for the customButton class !!!
someButton.onClick = buttonIsPressed;
LoginScreen buttonIsPressed():
loginPressedSignaller.fire(username, pass);
LoginScreenAuthenticator:
public var loginSuccessSignaller = new Signaller();
public var loginFailSignaller = new Signaller();
LoginScreenAuthenticator auth(username, pass):
socketConnection = !!! how do we use a socket connection here, if we cannot call a custom socket connection class !!!
socketConnection.write("login#auth#username#password");
This code is not finished yet, eg. I still have to listen for the server response, but you probably understand where I am getting stuck.
Question 2: Does this new structure make any sense? how should I solve the problems above mentioned in the !!! delimiters?
Then I heard about binders. So maybe I need to create a binder for each class, to connect everything together. Something like this:
MainBinder:
feature = new Main();
LoginScreenBinder:
feature = new LoginScreen();
MainBinder.feature.appLaunchedSignaller.bind(feature.load);
niceBackgroundLoader = loader.loadBitmap;
someButtonClass = gui.customButton();
etc... hopefully you understand what I mean. This post is getting a bit long so I have to wrap it up a bit.
Question 3: does this make any sense? Doesn't this make things unnecessarily complex?
Also, in the above "Binders" I only had to use classes which are instantiated once, eg. a login screen. What if there are multiple instances of a class, eg. a Player Class in a game of chess.
well, concerning the how, I would point out my 5 commandments to you. :)
For this question only 3 are really important:
single responsibility (SRP)
interface segregation (ISP)
dependency inversion (DIP)
Starting off with SRP, you have to ask yourself the question: "What is the responsibility of class X?".
The login screen is responsible for presenting an interface to the user to fill in and submit his login data. Thus
it makes sense for it to depend on the button class, because it needs the button.
it makes no sense it does all the networking etc.
First of all, you let's abstract the login service:
interface ILoginService {
function login(user:String, pwd:String, onDone:LoginResult->Void):Void;
//Rather than using signalers and what-not, I'll just rely on haXe's support for functional style,
//which renders these cumbersome idioms from more classic languages quite obsolete.
}
enum Result<T> {//this is a generic enum to return results from basically any kind of actions, that may fail
Fail(error:Int, reason:String);
Success(user:T);
}
typedef LoginResult = Result<IUser>;//IUser basically represent an authenticated user
From the point of view of the Main class, the login screen looks like this:
interface ILoginInterface {
function show(inputHandler:String->String->Void):Void;
function hide():Void;
function error(reason:String):Void;
}
performing login:
var server:ILoginService = ... //where ever it comes from. I will say a word about that later
var login:ILoginInterface = ... //same thing as with the service
login.show(function (user, pwd):Void {
server.login(user, pwd, function (result) {
switch (result) {
case Fail(_, reason):
login.error(reason);
case Success(user):
login.hide();
//proceed with the resulting user
}
});
});//for the sake of conciseness I used an anonymous function but usually, you'd put a method here of course
Now ILoginService looks a little titchy. But to be honest, it does all it needs to do. Now it can effectively be implemented by a class Server, that encapsulates all networking in a single class, having a method for each of the N calls your actual server provides, but first of all, ISP suggests, that many client specific interfaces are better than one general purpose interface. For the same reason ILoginInterface is really kept to its bare minimum.
No matter, how these two are actually implemented, you will not need to change Main (unless of course the interface changes). This is DIP being applied. Main doesn't depend on the concrete implementation, only on a very concise abstraction.
Now let's have some implementations:
class LoginScreen implements ILoginInterface {
public function show(inputHandler:String->String->Void):Void {
//render the UI on the screen
//wait for the button to be clicked
//when done, call inputHandler with the input values from the respective fields
}
public function hide():Void {
//hide UI
}
public function error(reason:String):Void {
//display error message
}
public static function getInstance():LoginScreen {
//classical singleton instantiation
}
}
class Server implements ILoginService {
function new(host:String, port:Int) {
//init connection here for example
}
public static function getInstance():Server {
//classical singleton instantiation
}
public function login(user:String, pwd:String, onDone:LoginResult->Void) {
//issue login over the connection
//invoke the handler with the retrieved result
}
//... possibly other methods here, that are used by other classes
}
Ok, that was pretty straight forward, I suppose. But just for the fun of it, let's do something really idiotic:
class MailLogin implements ILoginInterface {
public function new(mail:String) {
//save address
}
public function show(inputHandler:String->String->Void):Void {
//print some sort of "waiting for authentication"-notification on screen
//send an email to the given address: "please respond with username:password"
//keep polling you mail server for a response, parse it and invoke the input handler
}
public function hide():Void {
//remove the "waiting for authentication"-notification
//send an email to the given address: "login successful"
}
public function error(reason:String):Void {
//send an email to the given address: "login failed. reason: [reason] please retry."
}
}
As pedestrian as this authentication may be, from the point of view of the Main class,
this doesn't change anything and thus will work just as well.
A more likely scenario is actually, that your login service is on another server (possibly an HTTP server), that makes the authentication, and in case of success creates a session on the actual app server. Design-wise, this could be reflected in two separate classes.
Now, let's talk about the "..." I left in Main. Well, I'm lazy, so I can tell you, in my code you are likely to see
var server:ILoginService = Server.getInstance();
var login:ILoginInterface = LoginScreen.getInstance();
Of course, this is far from being the clean way to do it. The truth is, it's the easiest way to go and the dependency is limited to one occurrence, that can later be removed through dependency injection.
Just as a simple example for an IoC-Container in haXe:
class Injector {
static var providers = new Hash < Void->Dynamic > ;
public static function setProvider<T>(type:Class<T>, provider:Void->T):Void {
var name = Type.getClassName(type);
if (providers.exists(name))
throw "duplicate provider for " + name;
else
providers.set(name, provider);
}
public static function get<T>(type:Class<T>):T {
var name = Type.getClassName(type);
return
if (providers.exists(name))
providers.get(name);
else
throw "no provider for " + name;
}
}
elegant usage (with using keyword):
using Injector;
//wherever you would like to wire it up:
ILoginService.setProvider(Server.getInstance);
ILoginInterface.setProvider(LoginScreen.getInstance);
//and in Main:
var server = ILoginService.get();
var login = ILoginInterface.get();
This way, you practically have no coupling between the individual classes.
As to the question how to pass events between the button and the login screen:
this is just a matter of taste and implementation.
The point of event driven programming is that both the source and the observer are only coupled in the sense,
that the source must be sending some sort of notification and the target must be able to handle it.
someButton.onClick = handler; basically does exactly that, but it's just so elegant and concise you don't make a fuzz about it.
someButton.onClick(handler); probably is a little better, since you can have multiple handlers, although this is rarely required of UI components. But in the end, if you want signalers, go with signalers.
Now when it comes to AOP, it is not the right approach in this situation. It's not a clever hack to wire up components between one another, but about dealing with cross-cutting concerns, such as adding a log, a history or even things as a persistence layer across a multitude of modules.
In general, try not to modularize or split the little parts of your application.
It is ok to have some spaghetti in your codebase, as long as
the spaghetti segments are well encapsulated
the spaghetti segments are small enough to be understood or otherwise refactored/rewritten in a reasonable amount of time, without breaking the app (which point no. 1 should guarantee)
Try rather to split the whole application into autonomous parts, which interact through concise interfaces. If a part grows too big, refactor it just the same way.
edit:
In response to Tom's questions:
that's a matter of taste. in some frameworks people go as far as using external configuration files, but that makes little sense with haXe, since you need to instruct the compiler to force compilation of the dependencies you inject at runtime. Setting up the dependency in your code, in a central file, is just as much work and far simpler. For more structure, you can split the app into "modules", each module having a loader class responsible for registering the implementations it provides. In your main file, you load the modules.
That depends. I tend to declare them in the package of the class depending on them and later on refactor them to an extra package in case they prove to be needed elsewhere. By using anonymous types, you can also completely decouple things, but you'll have a slight performance hit on platforms as flash9.
I wouldn't abstract the button and then inject an implementation through IoC, but feel free to do so. I would explicitely create it, because in the end, it's just a button. It has a style, a caption, screen position and size and fires click events. I think, this is unnecessary modularization, as pointed out above.
Stick to SRP. If you do, no class will grow unneccessarily big. The role of the Main class is to initialize the app. When done, it should pass control to a login controller, and when that controller acquires a user object, it can pass it on to the main controller of the actual app and so forth. I suggest you read a bit about behavioral patterns to get some ideas.
greetz
back2dos
First of all, I'm not familiar with Haxe at all. However, I would answer that what is described here sounds remarkably similar to how I've learned to do things in .NET, so it sounds to me like this is good practice.
In .NET, you have an "Event" that fires when a user clicks a button to do something (like logon) and then a method executes to "handle" the event.
There will always be code that describes what method is executed in one class when an event in another class is fired. It is not unnecessarily complex, it is necessarily complex. In the Visual Studio IDE, much of this code is hidden in "designer" files, so I don't see it on a regular basis, but if your IDE doesn't have this functionality, you've got to write the code yourself.
As for how this works with your custom loader class, I hope someone here can provide you an answer.

Resources