There are no small libraries, not anymore. Actually, come to think of it, there are small libraries, they just aren't used by the application developer these days because the tools employed tend to be all-encompassing. That's the attempt anyway, and with valid reason too — I'm not going to like using toolkit X because I can't do Y. To do Y, I need toolkit Z. The less variability in the dependencies of my application, the happier I am as a developer. This over-arching attitude of mammoth libraries, however, creates a knowledge problem. The library tries to solve so many problems, that its size grows beyond what can fit in any one developer's head.
Showing posts with label library. Show all posts
Showing posts with label library. Show all posts
Wednesday, December 19, 2012
Monday, October 26, 2009
GUI Controller Design
The introduction of graphical user interfaces, or GUIs, have made a huge impact on the way humans interact with computer software. The command line, or terminal, interface is intimidating to many people. You can't exactly do anything intuitively with the command line unless you have several years experience using it. With the GUI, widgets, the components that make up the screen that is displayed to the user, are designed in such a way that they users can infer how to interact with them. For instance, with a button widget in a GUI, it is more often than not, obvious that the button should be clicked. In addition to the actions that the user must take in order to interact with the interface, the GUI allows for descriptive text to be easily placed. This helps the user determine why this button should be clicked instead of that one.
On the development side of things, there is no shortage today of GUI libraries available for use. Most of these libraries are available free of charge as open source software. Also very popular these days is the web browser as an application GUI platform. This is simply because most machines have a web browser capable of rendering HTML. It makes sense to take this approach to reach the widest audience possible.
The GUI library of choice, be it Qt or the web browser, is just one layer in the GUI design structure. In fact, it is the lowest level. Beyond the GUI library layer, that is a lower level still, are all aspects that the application developer doesn't want to deal with. What about the opposite direction in the logical layout of the GUI design structure? The next layer up could potentially be the application controlling layer itself. In many applications, this is in fact how components are layered. But this may not always be ideal. It can be beneficial for design purposes to implement a facade type abstraction in between the application logic and the various GUI widgets that make up application GUI. Illustrated below are potential layers that might be used to tie the GUI to the application itself.
Here, the outermost layer are the App Controllers. This is the heart of the application logic. It is the brain of the program that lives here. Next, we have GUI Controllers. This is another abstraction created by developers for interacting with the GUI library. Finally, at the lowest layer sits the GUI Lib. With this layout, the application logic never interacts directly with the GUI library which is an ideal design trait. GUI controllers created by the developers of the application offer more flexibility in almost every way imaginable.
Firstly, the application logic doesn't need to concern itself with assembling the GUI. Chances are that a given GUI library isn't going to provide the screens that you want to display to your users. They do, however, provide all widgets required to make for a consistent look and feel in the GUI. It is the responsibility of the GUI controlling layer to assemble these GUI widgets in a coherent manor. Again, the application logic only needs to know that it needs to display something to the user. It asks the GUI controlling layer to carry out this task faithfully. There is also the potential for technology independence. If the application controlling layer is interacting directly with the GUI library, modifying the application to support another GUI library is going to be nearly impossible. If, however, this is the responsibility of the GUI controlling layer, this suddenly becomes feasible. Not only does this help with technological independence, but also with platform portability. Chances are that subtle differences in how the widgets are created and displayed will be necessary across platforms. This should be done by the GUI controlling layer and not the application layer as it should function as-is on any platform.
Illustrated below is an application controller and a GUI controller interacting. The idea here is to show that the application controllers do not interact directly with the GUI library. In addition, the application controller servers as a communication channel to other lower layers. For instance, here, the page widget data is retrieved from the database by the application controller. The application controller then sends a message to the GUI controller to construct a GUI component. It sends data retrieved from the database as part of the message.
On the development side of things, there is no shortage today of GUI libraries available for use. Most of these libraries are available free of charge as open source software. Also very popular these days is the web browser as an application GUI platform. This is simply because most machines have a web browser capable of rendering HTML. It makes sense to take this approach to reach the widest audience possible.
The GUI library of choice, be it Qt or the web browser, is just one layer in the GUI design structure. In fact, it is the lowest level. Beyond the GUI library layer, that is a lower level still, are all aspects that the application developer doesn't want to deal with. What about the opposite direction in the logical layout of the GUI design structure? The next layer up could potentially be the application controlling layer itself. In many applications, this is in fact how components are layered. But this may not always be ideal. It can be beneficial for design purposes to implement a facade type abstraction in between the application logic and the various GUI widgets that make up application GUI. Illustrated below are potential layers that might be used to tie the GUI to the application itself.
Here, the outermost layer are the App Controllers. This is the heart of the application logic. It is the brain of the program that lives here. Next, we have GUI Controllers. This is another abstraction created by developers for interacting with the GUI library. Finally, at the lowest layer sits the GUI Lib. With this layout, the application logic never interacts directly with the GUI library which is an ideal design trait. GUI controllers created by the developers of the application offer more flexibility in almost every way imaginable.
Firstly, the application logic doesn't need to concern itself with assembling the GUI. Chances are that a given GUI library isn't going to provide the screens that you want to display to your users. They do, however, provide all widgets required to make for a consistent look and feel in the GUI. It is the responsibility of the GUI controlling layer to assemble these GUI widgets in a coherent manor. Again, the application logic only needs to know that it needs to display something to the user. It asks the GUI controlling layer to carry out this task faithfully. There is also the potential for technology independence. If the application controlling layer is interacting directly with the GUI library, modifying the application to support another GUI library is going to be nearly impossible. If, however, this is the responsibility of the GUI controlling layer, this suddenly becomes feasible. Not only does this help with technological independence, but also with platform portability. Chances are that subtle differences in how the widgets are created and displayed will be necessary across platforms. This should be done by the GUI controlling layer and not the application layer as it should function as-is on any platform.
Illustrated below is an application controller and a GUI controller interacting. The idea here is to show that the application controllers do not interact directly with the GUI library. In addition, the application controller servers as a communication channel to other lower layers. For instance, here, the page widget data is retrieved from the database by the application controller. The application controller then sends a message to the GUI controller to construct a GUI component. It sends data retrieved from the database as part of the message.
Labels:
architecture
,
controller
,
design
,
gui
,
library
,
responsibility
Friday, July 3, 2009
Subscribing To Event Subscritions In Python
New in the latest version of the boduch Python library is the Subscription class. This abstraction is used to represent active event subscriptions to event handles. A Subscription instance ties together the Event class and the Handle class. The Handle providing the callback functionality that is executed when a given event takes place that the handle as a subscription to. As with previous versions, the event handle still uses the subscribe() function to subscribe to particular events. However, in previous versions, this function didn't actually return anything. The function will now return a Subscription instance. This functionality was added so that developers can have an easier method in which to reference which events will cause a given behavior to take place. The following is an example of a Subscription instance being returned.
In the example above, we define a simple event handle called MyHandle. We then subscribe this handle to the EventSetPush event to instantiate a new Subscription instance. Each Subscription instance holds a reference to both the handle and the event that the handle has subscribed to. Additionally, Subscription instances also define behavior. Since a Subscription instance holds a reference to the given event, we can use this instance hold build further subscriptions for this event. The core event handles inside the library already define and expose Subscription instances and can be used to create subscriptions for new event handles as the example below illustrates.
#Example; Subscribing to a boduch Set event.
#Import required objects.
from boduch.event import subscribe, EventSetPush
from boduch.handle import Handle
from boduch.data import Set
#Simple handle.
class MyHandle(Handle):
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)
def run(self):
print "Running my handle."
if __name__=="__main__":
#Create a new subscription instance by subscribing to the event.
print "Subscribing"
sub=subscribe(EventSetPush, MyHandle)
print "Subscribed", sub
#Make sure the simple handle works.
Set().push("data")
#Example; Subscribing to a boduch Set event via subscription.
#Import required objects.
from boduch.subscription import SubSetPush
from boduch.handle import Handle
from boduch.data import Set
#Simple handle.
class MyHandle(Handle):
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)
def run(self):
print "Running my handle."
if __name__=="__main__":
#Create a new subscription instance by subscribing to the event.
print "Subscribing"
sub=SubSetPush.subscribe(MyHandle)
print "Subscribed", sub
#Make sure the simple handle works.
Set().push("data")
Saturday, March 14, 2009
Using predicates with the boduch library
With the latest release of the boduch Python library, there are two new predicate classes available; Greater and Lesser. These predicates do exactly what the name says. The Greater predicate will evaluate to true if the first operand is greater than the second. The Lesser predicate will return true if the first operand is less than the operand. Here is an example of how we would use these predicates.
Here, we have two predicate instances, is_greater and is_lesser. The is_greater variable is an instance of the Greater predicate and will evaluate to true in this case. The is_lesser variable is an instance of the Lesser predicate and will evaluate to true in this case.
With the latest release the library, predicate instances can also accept function objects as parameters. For example, consider the following modified example.
Here, we now have two variables, number1 and number2 that will act as operands. Next, we have two functions that will return these values, op1() and op2(). Next, the results() function simply prints the result of evaluating the predicates. In the main program, we construct the two predicate instances, passing the op1() and op2() functions as operand parameters. Next, we initialize the number1 and number2 variables and print the result of evaluating the predicates. Finally, we change the value of number1 and number2 and once more print the results. You'll notice that the results will have reflected the change in number1 and number2.
#Example; boduch predicates
from boduch.predicate import Greater, Lesser
if __name__=="__main__":
is_greater=Greater(2,1)
is_lesser=Lesser(1,2)
if is_greater:
print "is_greater is true."
else:
print "is_greater is false."
if is_lesser:
print "is_lesser is true."
else:
print "is_lesser is false"
Here, we have two predicate instances, is_greater and is_lesser. The is_greater variable is an instance of the Greater predicate and will evaluate to true in this case. The is_lesser variable is an instance of the Lesser predicate and will evaluate to true in this case.
With the latest release the library, predicate instances can also accept function objects as parameters. For example, consider the following modified example.
#Example; boduch predicates
from boduch.predicate import Greater, Lesser
number1=0
number2=0
def op1():
global number1
return number1
def op2():
global number2
return number2
def results():
global is_greater
global is_lesser
if is_greater:
print "is_greater is true."
else:
print "is_greater is false."
if is_lesser:
print "is_lesser is true."
else:
print "is_lesser is false"
if __name__=="__main__":
#Construct predicate instances using function objects as operands.
is_greater=Greater(op1,op2)
is_lesser=Lesser(op1,op2)
#Change the value of the operands.
number1=2
number2=1
#Print results.
results()
#Change the value of the operands.
number1=1
number2=2
#Print results.
results()
Here, we now have two variables, number1 and number2 that will act as operands. Next, we have two functions that will return these values, op1() and op2(). Next, the results() function simply prints the result of evaluating the predicates. In the main program, we construct the two predicate instances, passing the op1() and op2() functions as operand parameters. Next, we initialize the number1 and number2 variables and print the result of evaluating the predicates. Finally, we change the value of number1 and number2 and once more print the results. You'll notice that the results will have reflected the change in number1 and number2.
Wednesday, March 11, 2009
Interesting bug found in the boduch Python library
In the latest release of the boduch Python library, Set instances can now be iterated over. This is done by defining a custom iterator class, SetIterator, that is returned by the Set.__iter__() method. I thought I would further test out this new functionality in a hope that I would discover some new unit tests that I can include with the library. But before I could even get to the Set iteration testing, I discovered an entirely new bug with the Set class.
Firstly, here is the code I used to find the bug.
Here, we defined a custom event handle called MyHandle. I the run method doesn't actually do anything because I discovered the bug before I wrote any handling code. In the main program, we set the event manager to threaded mode. Next, we subscribe our custom event handle to the EventSetPush event. This means that every time Set.push() is invoked, so is MyHandle.run() (in a new thread since we are running in threaded mode here). We then create two set instances and push some data onto each set. Finally, we print the underlying Python lists associated with each set instance.
Here is my initial output.
Slightly different from what was expected. Each set instance should have had one element each. Instead, the lists look identical. Naturally, I assumed that they were the same list. This lead me to start examining the thread manager, thinking that since I was testing in threaded mode, there must be some sort of cross-thread data contamination. Thankfully, the problem got much simpler since I was able to eliminate this as a potential cause. Next in line, the event manager. I tried everything to try and prove that the Set instances were in fact the same instance. Not so. The instances had different memory addresses.
I then realized that Set inherits from Type but the constructor for type is not invoked. Odd. I tried to think of a reason why I would want to inherit something with no static functionality and not initialize it. I think I may have done this because the underlying list instances of Set objects are stored in an attribute called data. Type instances also define a data attribute. I must have thought, during the original implementation, that defining a data attribute for the Set class would have some adverse effect on the Type functionality. Not so. So now, the Type constructor is invoked but with no parameters. This means that the initial value of the Set.data attribute is actually an empty dictionary since this is what the Type constructor will initialize it as. The Set constructor will then initialize the data attribute to a list accordingly.
This however, wasn't the problem either. I was still getting the strange output that pointed so convincingly at the fact that the Set.data attribute was pointing to the same list instance. So, I took a look at the way in which the data attribute is initialized for Set instances. The Set constructor will accept a data keyword parameter. The default value of this parameter is an empty list. This parameter then becomes the Set.data attribute. Just for fun, I decided to take away this parameter and have the data attribute be initialized as an empty list inside the constructor.
Sure enough, that did it. I got the correct output for my two set instances. The data attribute must have been pointing to the same keyword parameter variable. I have a felling that this may be caused somewhere in the event manager. Or maybe not. I haven't tested this scenario outside the library yet.
I'm going to get this release out as soon as possible. The data keyword parameter for the Set constructor will be removed for now. As a side note, this will also affect the iteration functionality for Hash instances in the next release since the Hash.__iter__() method will return a SetIterator instance containing the hash keys. Each key will simply need to be pushed onto the set instead.
Firstly, here is the code I used to find the bug.
#Example; boduch Set bug.
from boduch.data import Set
from boduch.handle import Handle
from boduch.event import subscribe, threaded, EventSetPush
class MyHandle(Handle):
def __init__(self, *args, **kw):
Handle.__init__(self, *args, **kw)
def run(self):
pass
if __name__=="__main__":
threaded(True)
subscribe(EventSetPush, MyHandle)
set_obj1=Set()
set_obj2=Set()
set_obj1.push("data1")
set_obj2.push("data2")
print "SET1",set_obj1.data
print "SET2",set_obj2.data
Here is my initial output.
SET1 ['data1', 'data2']
SET2 ['data1', 'data2']
I then realized that Set inherits from Type but the constructor for type is not invoked. Odd. I tried to think of a reason why I would want to inherit something with no static functionality and not initialize it. I think I may have done this because the underlying list instances of Set objects are stored in an attribute called data. Type instances also define a data attribute. I must have thought, during the original implementation, that defining a data attribute for the Set class would have some adverse effect on the Type functionality. Not so. So now, the Type constructor is invoked but with no parameters. This means that the initial value of the Set.data attribute is actually an empty dictionary since this is what the Type constructor will initialize it as. The Set constructor will then initialize the data attribute to a list accordingly.
This however, wasn't the problem either. I was still getting the strange output that pointed so convincingly at the fact that the Set.data attribute was pointing to the same list instance. So, I took a look at the way in which the data attribute is initialized for Set instances. The Set constructor will accept a data keyword parameter. The default value of this parameter is an empty list. This parameter then becomes the Set.data attribute. Just for fun, I decided to take away this parameter and have the data attribute be initialized as an empty list inside the constructor.
Sure enough, that did it. I got the correct output for my two set instances. The data attribute must have been pointing to the same keyword parameter variable. I have a felling that this may be caused somewhere in the event manager. Or maybe not. I haven't tested this scenario outside the library yet.
I'm going to get this release out as soon as possible. The data keyword parameter for the Set constructor will be removed for now. As a side note, this will also affect the iteration functionality for Hash instances in the next release since the Hash.__iter__() method will return a SetIterator instance containing the hash keys. Each key will simply need to be pushed onto the set instead.
Wednesday, March 4, 2009
Using predicates with the boduch library
The boduch Python library has a new Predicate class that can be used to evaluate predicates. The Predicate class is meant to be an abstract super class. As of the 0.1.2 release of the library, there is only an Equal predicate. This predicate can be used to test the equality of two specified values. For example, consider the following.
In this example, we define two string values; val1 and val2. We then use the Equal predicate as our loop condition. The Equal predicate will always evaluate to true as long as the two specified operators are equal. The Equal predicate uses the == Python operator to evaluate the result. So, why bother with the boduch predicates? One reason would be consistency if you are using the library elsewhere in the application. Another reason may be readability.
The Equal predicate is actually a Python class. Every time we instantiate Equal(), we are actually evaluating against an Equal instance. The equal predicate defines overloaded operators that handle the comparison when the instance is used in that context. There are also events and handles for predicates in the boduch library. If necessary, other handles may subscribe to these events. However, the events published by predicates in the boduch library are atomic. This means that no new threads will be started for these handles.
The next release of the library should have some more interesting predicates such as Greater and Less.
#Example; Using the boduch.predicate.Equal predicate.
from boduch.predicate import Equal
if __name__=="__main__":
val1="My Value"
val2="My Value"
while Equal(val1, val2):
print "Changing val1 in order to exit our loop."
val1="Exit"
print val1
The Equal predicate is actually a Python class. Every time we instantiate Equal(), we are actually evaluating against an Equal instance. The equal predicate defines overloaded operators that handle the comparison when the instance is used in that context. There are also events and handles for predicates in the boduch library. If necessary, other handles may subscribe to these events. However, the events published by predicates in the boduch library are atomic. This means that no new threads will be started for these handles.
The next release of the library should have some more interesting predicates such as Greater and Less.
Thursday, February 12, 2009
boduch 0.1.1
The 0.1.1 version of the boduch Python library is now available. Some changes include:
As you can see, we can now treat Set and Hash instances as though they were Python list and dictionary instances respectively. The main difference being of course, all actions are carried out by event handlers. This enables threaded behaviour for some of the actions. For example, pushing new items and updating existing items will be handled in separate threads if threading is enabled.
- New Set and Hash functionality. Both object types now support the Python key/index notation.
- More unit tests.
#Example; boduch data types.
from boduch.data import Set, Hash
from boduch.event import threaded
def test_set_data():
set_obj=Set()
set_obj.push("test1")
set_obj.push("test2")
print "SET:",set_obj[0]
print "SET:",set_obj[1]
set_obj[0]="updated test1"
set_obj[1]="updated test2"
print "SET:",set_obj[0]
print "SET:",set_obj[1]
del set_obj[0]
del set_obj[0]
def test_hash_data():
hash_obj=Hash()
hash_obj.push(("test1", "value1"))
hash_obj.push(("test2", "value1"))
print "HASH:",hash_obj["test1"]
print "HASH:",hash_obj["test2"]
hash_obj["test1"]="updated value1"
hash_obj["test2"]="updated value2"
print "HASH:",hash_obj["test1"]
print "HASH:",hash_obj["test2"]
del hash_obj["test1"]
del hash_obj["test2"]
if __name__=="__main__":
test_set_data()
test_hash_data()
threaded(True)
test_set_data()
test_hash_data()
Monday, February 9, 2009
Testing types with boduch
The boduch Python library provides a simple type testing utility function that allows truth tests for both primitive and user-defined data types. Python does offer built-in type testing utilities, but there is currently no unification between user-defined classes and primitive types. Here is an example of how to use the is_type() function.
As you can see, we can significantly cut down the number of lines required for type testing with a single function. Also note, is_type() can also test if the specified instance belongs in an inheritance lattice, as demonstrated in this example.
#boduch type testing example.
from boduch.type import is_type
class MyBaseType:
pass
class MyType(MyBaseType):
pass
if __name__=="__main__":
print "Testing string type."
print is_type("my string", "str")
print "Testing boolean type."
print is_type(False, "boolean")
print "Testing a class type."
print is_type(MyType(), "MyType")
print "Testing for a base class."
print is_type(MyType(), "MyBaseType")
Sunday, February 1, 2009
boduch 0.1.0
The 0.1.0 release of the boduch Python library is now available. Changes:
- Minor release.
- Refactored the interface package.
- More API documentation.
Wednesday, January 28, 2009
Monday, January 26, 2009
boduch 0.0.9
The 0.0.9 release of the boduch Python library is now available. Changes include:
- Completely replaced the LockManager class. The locking primitives for exchanging data between event threads is now handled by the Python queue module.
- Added a new atomic parameter to the EventManager.publish() method. This allows handles to be executed by the same thread that published the event. Event when the event manager is running in threaded mode.
- Added a new max_threads attribute to the ThreadManager class. This is the maximum number of threads allowed to execute.
Friday, January 23, 2009
boduch 0.0.8
The 0.0.8 release of the boduch Python library is now available. Changes include:
- Implemented a new ThreadManager. This takes the responsibility of starting new threads away from the EventManager.
- Created a new data package in boduch.event for the Set and Hash events.
- Created a new data package in boduch.handle for the Set and Hash handles.
- Minor bug fixes.
Saturday, January 17, 2009
boduch 0.0.7
The 0.0.7 release of the boduch Python package is now available. Changes include:
- Implemented a new LockManager class for locking in threaded event handles.
- Made some enhancements to the is_type() utility function.
- Created some new type constants.
Tuesday, January 13, 2009
boduch 0.0.6
The 0.0.6 version of the boduch Python package is now available. Changes include:
- Fixed a major bug in EventManager.subscribe() that allowed the same handle for a single event to be subscribed more than once.
- Type instances now have a uuid attribute which is generated by the constructor.
- EventThread will now inherit from Type.
- Improved the EventManager interface.
- Improved the Event and Handle interfaces.
- Implemented new Set and Hash event handles.
Friday, January 9, 2009
boduch 0.0.5
The 0.0.5 version of the boduch Python library is now available. This is a minor release:
- Added more unit tests.
- Added more API documentation.
Tuesday, January 6, 2009
boduch 0.0.4
The boduch 0.0.4 Python tool library has been released. Some of the changes are:
- Fixed a minor bug in the ISet interface.
- The new Hash data type with event emission has been implemented.
- Implemented a new handle for EventSetPush events.
Monday, January 5, 2009
New in boduch 0.0.4
I thought I'd mention what is going on development-wise in the boduch Python library. The upcoming 0.0.4 release has a new handler for EventSetPush events. This handler is what actually pushes data onto the set instance that produces the event. Typically, there is no point. The push() method may as well be responsible for actually pushing the data onto the set instance.
There are cases where we may want to send the data being pushed somewhere remote in addition to the set. Also, when creating reactive interfaces that "sit on top of" the library, this could potentially increase the responsiveness.
There will also be a new Hash data type. This data type is essentially a Python dictionary that will emit events. It will follow a similar interface as that provided by the Set data type.
There are cases where we may want to send the data being pushed somewhere remote in addition to the set. Also, when creating reactive interfaces that "sit on top of" the library, this could potentially increase the responsiveness.
There will also be a new Hash data type. This data type is essentially a Python dictionary that will emit events. It will follow a similar interface as that provided by the Set data type.
Subscribe to:
Posts
(
Atom
)