Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Save more on your purchases! discount-offer-chevron-icon
Savings automatically calculated. No voucher code required.
Arrow left icon
All Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Newsletter Hub
Free Learning
Arrow right icon
timer SALE ENDS IN
0 Days
:
00 Hours
:
00 Minutes
:
00 Seconds

How-To Tutorials - Programming

1081 Articles
article-image-troux-enterprise-architecture-managing-ea-function
Packt
25 Aug 2010
9 min read
Save for later

Troux Enterprise Architecture: Managing the EA function

Packt
25 Aug 2010
9 min read
(For more resources on Troux, see here.) Targeted charter Organizations need a mission statement and charter. What should the mission and charter be for EA? The answer to this question depends on how the CIO views the function and where the function resides on the maturity model. The CIO could believe that EA should be focused on setting standards and identifying cost reduction opportunities. Conversely, the CIO could believe the function should focus on evaluation of emerging technologies and innovation. These two extremes are polar opposites. Each would require a different staffing model and different success criteria. The leader of EA must understand how the CIO views the function, as well as what the culture of the business will accept. Are IT and the business familiar with top-down direction, or does the company normally follow a consensus style of management? Is there a market leadership mentality or is the company a fast follower regarding technical innovation? To run a successful EA operation, the head of Enterprise Architecture needs to understand these parameters and factor them into the overall direction of the department. The following diagram illustrates finding the correct position between the two extremes of being focused on standards or innovation: Using standards to enforce polices on a culture that normally works through consensus will not work very well. Also, why focus resources on developing a business strategy or evaluating emerging technology if the company is totally focused on the next quarter's financial results? Sometimes, with the appropriate support from the CIO and other upper management, EA can become the change agent to encourage long-term planning. If a company has been too focused on tactics, EA can be the only department in IT that has the time and resources available to evaluate emerging solutions. The leader of the architecture function must understand the overall context in which the department resides. This understanding will help to develop the best structure for the department and hire people with the correct skill set. Let us look at the organization structure of the EA function. How large should the department be, where should the department report, and what does the organization structure look like? In most cases, there are also other areas within IT that perform what might be considered EA department responsibilities. How should the structure account for "domain architects" or "application architects" who do not report to the head of Enterprise Architecture? As usual, the answer to these questions is "it depends". The architecture department can be sized appropriately with an understanding of the overall role Enterprise Architecture plays within the broader scope of IT. If EA also runs the project management office (PMO) for IT, then the department is likely to be as large as fifty or more resources. In the case where the PMO resides outside of architecture, the architecture staffing level is normally between fifteen and thirty people. To be effective in a large enterprise, (five hundred or more applications development personnel) the EA department should be no smaller than about fifteen people. The following diagram provides a sample organization chart that assumes a balance is required between being focused on technical governance and IT strategy: The sample organization chart shows the balance between resources applied to tactical work and strategic work. The left side of the chart shows the teams focused on governance. Responsibilities include managing the ARB and maintaining standards and the architecture website. An architecture website is critical to maintaining awareness of the standards and best practices developed by the EA department. The sample organizational model assumes that a team of Solution Architects is centralized. These are experienced resources who help project teams with major initiatives that span the enterprise. These resources act like internal consultants and, therefore, must possess a broad spectrum of skills. Depending on the overall philosophy of the CIO, the Domain Architects may also be centralized. These are people with a high degree of experience within specific major technical domains. The domains match to the overall architectural framework of the enterprise and include platforms, software (including middleware), network, data, and security. These resources could also be decentralized into various applications development or engineering groups within IT. If Domain Architects are decentralized, at least two resources are needed within EA to ensure that each area is coordinated with the others across technical disciplines. If EA is responsible for evaluation of emerging technologies, then a team is needed to focus on execution of proof-of-architecture projects and productivity tool evaluations. A service can be created to manage various contracts and relationships with outside consulting agencies. These are typically companies focused on providing research, tracking IT advancements, and, in some cases, monitoring technology evolution within the company's industry. There are leaders (management) in each functional area within the architecture organization. As the resources under each area are limited, a good practice is to assume the leadership positions are also working positions. Depending on the overall culture of the company, the leadership positions could be Director- or Manager-level positions. In either case, these leaders must work with senior leaders across IT, the business, and outside vendors. For this reason, to be effective, they must be people with senior titles granted the authority to make important recommendations and decisions on a daily basis. In most companies, there is considerable debate about whether standards are set by the respective domain areas or by the EA department. The leader of EA, working with the CIO or CTO, must be flexible and able to adapt to the culture. If there is a need to centralize, then the architecture team must take steps to ensure there is buy-in for standards and ensure that governance processes are followed. This is done by building partnerships with the business and IT areas that control the allocation of funds to important projects. If the culture believes in decentralized standards management, then the head of architecture must ensure that there is one, and only one, official place where standards are documented and managed. The ARB, in this case, becomes the place where various opinions and viewpoints are worked out. However, it must be clear that the ARB is a function of Enterprise Architecture, and those that do not follow the collaborative review processes will not be able to move forward without obtaining a management consensus. Staffing the function Staffing the EA function is a challenge. To be effective, the group must have people who are respected for their technical knowledge and are able to communicate well using consensus and collaboration techniques. Finding people with the right combination of skills is difficult. Enterprise Architects may require higher salaries as compared to other staff within IT. Winning the battle with the human resources department about salaries and reporting levels within the corporate hierarchy is possible through the use of industry benchmarks. Requesting that jobs be evaluated against similar roles in the same industry will help make the point about what type of people are needed within the architecture department. People working in the EA department are different and here's why. In baseball, professional scouts rate prospects according to a scale on five different dimensions. Players that score high on all five are called "five tool players." These include hitting, hitting for power, running speed, throwing strength, and fielding. In evaluating resources for EA, there are also five major dimensions to consider. These include program management, software architecture, data architecture, network architecture, and platform architecture. As the following figure shows, an experience scale can be established for each dimension, yielding a complete picture of a candidate. People with the highest level of attainment across all five dimensions would be "five tool players". To be the most flexible in meeting the needs of the business and IT, the head of EA should strive for a good mix of resources covering the five dimensions. Resources who have achieved level 4 or level 5 across all of these would be the best candidates for the Solution Architect positions. These resources can do almost anything technical and are valuable across a wide array of enterprise-wide projects and initiatives. Resources who have mastered a particular dimension, such as data architecture or network architecture, are the best candidates for the Domain Architect positions. Software architecture is a broad dimension that includes software design, industry best practices, and middleware. Included within this area would be resources skilled in application development using various programming languages and design styles like object-oriented programming and SOA. As already seen, the Business Architect role spans all IT domains. The best candidates for Business Architecture need not be proficient in the five disciplines of IT architecture, but they will do a better job if they have a good awareness of what IT Architects do. Business Architects may be centralized and report into the EA function, or they may be decentralized across IT or even reside within business units. They are typically people with deep knowledge of business functions, business processes, and applications. Business Architects must be good communicators and have strong analytical abilities. They should be able to work without a great deal of supervision, be good at planning work, and can be trusted to deliver results per a schedule. Following are some job descriptions for these resources. They are provided as samples because each company will have its own unique set. Vice President/Director of Enterprise Architecture The Vice President/Director of Enterprise Architecture would normally have more than 10 or 15 years of experience depending on the circumstances of the organization. He or she would have experience with, and probably has mastered, all five of the key architecture skill set dimensions. The best resource is one with superior communication skills who is able to effect change across large and diverse organizations. The resource will also have experience within the industry in which the company competes. Leadership qualities are the most important aspect of this role, but having a technical background is also important. This person must be able to translate complex ideas, technology, and programs into language upper management can relate to. This person is a key influencer on technical decisions that affect the business on a long-term basis.
Read more
  • 0
  • 0
  • 3123

article-image-python-image-manipulation
Packt
12 Aug 2010
5 min read
Save for later

Python Image Manipulation

Packt
12 Aug 2010
5 min read
(For more resources on Python, see here.) So let's get on with it! Installation prerequisites Before we jump in to the main topic, it is necessary to install the following packages. Python In this article, we will use Python Version 2.6, or to be more specific, Version 2.6.4. It can be downloaded from the following location: http://python.org/download/releases/ Windows platform For Windows, just download and install the platform-specific binary distribution of Python 2.6.4. Other platforms For other platforms, such as Linux, Python is probably already installed on your machine. If the installed version is not 2.6, build and install it from the source distribution. If you are using a package manager on a Linux system, search for Python 2.6. It is likely that you will find the Python distribution there. Then, for instance, Ubuntu users can install Python from the command prompt as: $sudo apt-get python2.6 Note that for this, you must have administrative permission on the machine on which you are installing Python. Python Imaging Library (PIL) We will learn image-processing techniques by making extensive use of the Python Imaging Library (PIL) throughout this article. PIL is an open source library. You can download it from http://www.pythonware.com/products/pil/. Install the PIL Version 1.1.6 or later. Windows platform For Windows users, installation is straightforward—use the binary distribution PIL 1.1.6 for Python 2.6. Other platforms For other platforms, install PIL 1.1.6 from the source. Carefully review the README file in the source distribution for the platform-specific instructions. Libraries listed in the following table are required to be installed before installing PIL from the source. For some platforms like Linux, the libraries provided in the OS should work fine. However, if those do not work, install a pre-built "libraryName-devel" version of the library. For example, for JPEG support, the name will contain "jpeg-devel-", and something similar for the others. This is generally applicable to rpm-based distributions. For Linux flavors like Ubuntu, you can use the following command in a shell window. $sudo apt-get install python-imaging However, you should make sure that this installs Version 1.1.6 or later. Check PIL documentation for further platform-specific instructions. For Mac OSX, see if you can use fink to install these libraries. See http://www.finkproject.org/ for more details. You can also check the website http://pythonmac.org or Darwin ports website http://darwinports.com/ to see if a binary package installer is available. If such a pre-built version is not available for any library, install it from the source. The PIL prerequisites for installing PIL from source are listed in the following table: Library URL Version Installation options (a) or (b) libjpeg (JPEG support) http://www.ijg.org/files 7 or 6a or 6b (a) Pre-built version. For example: jpeg-devel-7 Check if you can do: sudo apt-install libjpeg (works on some flavors of Linux) (b) Source tarball. For example: jpegsrc.v7.tar.gz zib (PNG support) http://www.gzip.org/zlib/ 1.2.3 or later (a) Pre-built version. For example: zlib-devel-1.2.3.. (b) Install from the source. freetype2 (OpenType /TrueType support) http://www.freetype.org 2.1.3 or later (a) Pre-built version. For example: freetype2-devel-2.1.3.. (b) Install from the source. PyQt4 This package provides Python bindings for Qt libraries. We will use PyQt4 to generate GUI for the image-processing application that we will develop later in this article. The GPL version is available at: http://www.riverbankcomputing.co.uk/software/pyqt/download. Windows platform Download and install the binary distribution pertaining to Python 2.6. For example, the executable file's name could be 'PyQt-Py2.6-gpl-4.6.2-2.exe'. Other than Python, it includes everything needed for GUI development using PyQt. Other platforms Before building PyQt, you must install SIP Python binding generator. For further details, refer to the SIP homepage: http://www.riverbankcomputing.com/software/sip/. After installing SIP, download and install PyQt 4.6.2 or later, from the source tarball. For Linux/Unix source, the filename will start with PyQt-x11-gpl-.. and for Mac OS X, PyQt-mac-gpl-... Linux users should also check if PyQt4 distribution is already available through the package manager. Summary of installation prerequisites   Package Download location Version Windows platform Linux/Unix/OS X platforms Python http://python.org/download/releases/ 2.6.4 (or any 2.6.x) Install using binary distribution (a) Install from binary; Also install additional developer packages (For example, with python-devel in the package name in the rpm systems) OR (b) Build and install from the source tarball. (c) MAC users can also check websites such as http://darwinports.com/ or http://pythonmac.org/. PIL http://www.pythonware.com/products/pil/ 1.1.6 or later Install PIL 1.1.6 (binary) for Python 2.6 (a) Install prerequisites if needed. Refer to Table #1 and the README file in PIL source distribution. (b) Install PIL from source. (c) MAC users can also check websites like http://darwinports.com/ or http://pythonmac.org/. PyQt4 http://www.riverbankcomputing.co.uk/software/pyqt/download 4.6.2 or later Install using binary pertaining to Python 2.6 (a) First install SIP 4.9 or later. (b) Then install PyQt4.
Read more
  • 0
  • 0
  • 6382

article-image-python-multimedia-application-thumbnail-maker
Packt
12 Aug 2010
7 min read
Save for later

A Python Multimedia Application: Thumbnail Maker

Packt
12 Aug 2010
7 min read
(For more resources on Python, see here.) Project: Thumbnail Maker Let's take up a project now. We will apply some of the operations we learned in the previous article, to create a simple Thumbnail Maker utility. This application will accept an image as an input and will create a resized image of that image. Although we are calling it a thumbnail maker, it is a multi-purpose utility that implements some basic image-processing functionality. Before proceeding further, make sure that you have installed all the packages discussed at the beginning of the previous article. The screenshot of the Thumbnail Maker dialog is show in the following illustration. The Thumbnail Maker GUI has two components: The left panel is a 'control area', where you can specify certain image parameters along with options for input and output paths. A graphics area on the right-hand side where you can view the generated image. In short, this is how it works: The application takes an image file as an input. It accepts user input for image parameters such as dimensions in pixel, filter for re-sampling and rotation angle in degrees. When the user clicks the OK button in the dialog, the image is processed and saved at a location indicated by the user in the specified output image format. Time for action – play with Thumbnail Maker application First, we will run the Thumbnail Maker application as an end user. This warm-up exercise intends to give us a good understanding of how the application works. This, in turn, will help us develop/learn the involved code quickly. So get ready for action! Download the files ThumbnailMaker.py, ThumbnailMakeDialog.py, and Ui_ThumbnailMakerDialog.py from Packt website. Place these files in some directory. From the command prompt, change to this directory location and type the following command: python ThumbnailMakerDialog.py The Thumbnail Maker dialog that pops up was shown in the earlier screenshot. Next, we will specify the input-output paths and various image parameters. You can open any image file of your choice. Here, the flower image shown in some previous sections will be used as an input image. To specify an input image, click on the small button with three dots …. It will open a file dialog. The following illustration shows the dialog with all the parameters specified. If "Maintain Aspect Ratio" checkbox is checked, internally it will scale the image dimension so that the aspect ratio of the output image remains the same. When the OK button is clicked, the resultant image is saved at the location specified by the Output Location field and the saved image is displayed in the right-hand panel of the dialog. The following screenshot shows the dialog after clicking OK button. You can now try modifying different parameters such as output image format or rotation angle and save the resulting image. See what happens when the Maintain Aspect Ratio checkbox is unchecked. The aspect ratio of the resulting image will not be preserved and the image may appear distorted if the width and height dimensions are not properly specified. Experiment with different re-sampling filters; you can notice the difference between the quality of the resultant image and the earlier image. There are certain limitations to this basic utility. It is required to specify reasonable values for all the parameters fields in the dialog. The program will print an error if any of the parameters is not specified. What just happened? We got ourselves familiar with the user interface of the thumbnail maker dialog and saw how it works for processing an image with different dimensions and quality. This knowledge will make it easier to understand the Thumbnail Maker code. Generating the UI code The Thumbnail Maker GUI is written using PyQt4 (Python bindings for Qt4 GUI framework). Detailed discussion on how the GUI is generated and how the GUI elements are connected to the main functions is beyond the scope of this article. However, we will cover certain main aspects of this GUI to get you going. The GUI-related code in this application can simply be used 'as-is' and if this is something that interests you, go ahead and experiment with it further! In this section, we will briefly discuss how the UI code is generated using PyQt4. Time for action – generating the UI code PyQt4 comes with an application called QT Designer. It is a GUI designer for QT-based applications and provides a quick way to develop a graphical user interface containing some basic widgets. With this, let's see how the Thumbnail Maker dialog looks in QT Designer and then run a command to generate Python source code from the .ui file. Download the thumbnailMaker.ui file from the Packt website. Start the QT Designer application that comes with PyQt4 installation. Open the file thumbnailMaker.ui in QT Designer. Notice the red-colored borders around the UI elements in the dialog. These borders indicate a 'layout' in which the widgets are arranged. Without a layout in place, the UI elements may appear distorted when you run the application and, for instance, resize the dialog. Three types of QLayouts are used, namely Horizontal, Vertical, and Grid layout. You can add new UI elements, such as a QCheckbox or a QLabel, by dragging and dropping it from the 'Widget Box' of QT Designer. It is located in the left panel by default. Click on the field next to the label "Input file". In the right-hand panel of QT Designer, there is a Property Editor that displays the properties of the selected widget (in this case it's a QLineEdit). This is shown in the following illustration. The Property Editor allows us to assign values to various attributes such as the objectName, width, and height of the widget, and so on. Qt Designer shows the details of the selected widget in Property Editor. QT designer saves the file with extension .ui. To convert this into Python source code, PyQt4 provides a conversion utility called pyuic4. On Windows XP, for standard Python installation, it is present at the following location—C:Python26 Libsite-packagesPyQt4pyuic4.bat. Add this path to your environment variable. Alternatively specify the whole path each time you want to convert ui file to Python source file. The conversion utility can be run from the command prompt as: pyuic4 thumbnailMaker.ui -o Ui_ThumbnailMakerDialog.py This script will generate Ui_ThumbnailMakerDialog.py with all the GUI elements defined. You can further review this file to understand how the UI elements are defined. What just happened? We learned how to autogenerate the Python source code defining UI elements of Thumbnail Maker Dialog from a Qt designer file. Have a go hero – tweak UI of Thumbnail Maker dialog Modify the thumbnailMaker.ui file in QT Designer and implement the following list of things in the Thumbnail Maker dialog. Change the color of all the line edits in the left panel to pale yellow. Tweak the default file extension displayed in the Output file Format combobox such that the first option is .png instead of .jpeg Double click on this combobox to edit it. Add new option .tiff to the output format combobox. Align the OK and Cancel buttons to the right corner. You will need to break layouts, move the spacer around, and recreate the layouts. Set the range of rotation angle 0 to 360 degrees instead of the current -180 to +180 degrees. After this, create Ui_ThumbnailMakerDialog.py by running the pyuic4 script and then run the Thumbnail Maker application.
Read more
  • 0
  • 0
  • 5152
Visually different images

article-image-python-3-object-oriented-programming-managing-objects
Packt
12 Aug 2010
9 min read
Save for later

Python 3 Object Oriented Programming: Managing objects

Packt
12 Aug 2010
9 min read
(For more resources on Python 3, see here.) Managing objects The difference between these objects and most of the examples we've seen so far is that our examples tend to represent concrete ideas. Management objects are more like office managers; they don't do the actual "visible" work out on the floor, but without them, there would be no communication between departments and nobody would know what they are supposed to do. Analogously, the attributes on a management class tend to refer to other objects that do the "visible" work; the behaviors on such a class delegate to those other classes at the right time, and pass messages between them. As an example, we'll write a program that does a find and replace action for text files stored in a compressed ZIP file. We'll need objects to represent the ZIP file and each individual text file (luckily, we don't have to write these classes, they're available in the Python Standard Library). The manager object will be responsible for ensuring three steps occur in order: Unzipping the compressed file. Performing the find and replace action. Zipping up the new files. The class is initialized with the .zip filename and search and replace strings. We create a temporary directory to store the unzipped files in, so that the folder stays clean. We also add a useful helper method for internal use that helps identify an individual filename inside that directory: import sysimport osimport shutilimport zipfileclass ZipReplace: def __init__(self, filename, search_string, replace_string): self.filename = filename self.search_string = search_string self.replace_string = replace_string self.temp_directory = "unzipped-{}".format( filename) def _full_filename(self, filename): return os.path.join(self.temp_directory, filename) Then we create an overall "manager" method for each of the three steps. This method delegates responsibility to other methods. Obviously, we could do all three steps in one method, or indeed, in one script without ever creating an object. There are several advantages to separating the three steps: Readability: The code for each step is in a self-contained unit that is easy to read and understand. The method names describe what the method does, and no additional documentation is required to understand what is going on. Extensibility: If a subclass wanted to use compressed TAR files instead of ZIP files, it could override the zip and unzip methods without having to duplicate the find_replace method. Partitioning: An external class could create an instance of this class and call the find and replace method directly on some folder without having to zip the content. The delegation method is the first in the code below; the rest of the methods are included for completeness: def zip_find_replace(self): self.unzip_files() self.find_replace() self.zip_files() def unzip_files(self): os.mkdir(self.temp_directory) zip = zipfile.ZipFile(self.filename) try: zip.extractall(self.temp_directory) finally: zip.close() def find_replace(self): for filename in os.listdir(self.temp_directory): with open(self._full_filename(filename)) as file: contents = file.read() contents = contents.replace( self.search_string, self.replace_string) with open( self._full_filename(filename), "w") as file: file.write(contents) def zip_files(self): file = zipfile.ZipFile(self.filename, 'w') for filename in os.listdir(self.temp_directory): file.write( self._full_filename(filename), filename) shutil.rmtree(self.temp_directory)if __name__ == "__main__": ZipReplace(*sys.argv[1:4]).zip_find_replace() For brevity, the code for zipping and unzipping files is sparsely documented. Our current focus is on object-oriented design; if you are interested in the inner details of the zipfile module, refer to the documentation in the standard library, either online at http://docs.python.org/library/zipfile.html or by typing import zipfile ; help(zipfile) into your interactive interpreter. Note that this example only searches the top-level files in a ZIP file; if there are any folders in the unzipped content, they will not be scanned, nor will any files inside those folders. The last two lines in the code allow us to run the example from the command line by passing the zip filename, search string, and replace string as arguments: python zipsearch.py hello.zip hello hi Of course, this object does not have to be created from the command line; it could be imported from another module (to perform batch ZIP file processing) or accessed as part of a GUI interface or even a higher-level management object that knows what to do with ZIP files (for example to retrieve them from an FTP server or back them up to an external disk). As programs become more and more complex, the objects being modeled become less and less like physical objects. Properties are other abstract objects and methods are actions that change the state of those abstract objects. But at the heart of every object, no matter how complex, is a set of concrete properties and well-defined behaviors. Removing duplicate code Often the code in management style classes such as ZipReplace is quite generic and can be applied in many different ways. It is possible to use either composition or inheritance to help keep this code in one place, thus eliminating duplicate code. Before we look at any examples of this, let's discuss a tiny bit of theory. Specifically: why is duplicate code a bad thing? There are several reasons, but they all boil down to readability and maintainability. When we're writing a new piece of code that is similar to an earlier piece, the easiest thing to do is copy the old code and change whatever needs to change (variable names, logic, comments) to make it work in the new location. Alternatively, if we're writing new code that seems similar, but not identical to code elsewhere in the project, the easiest thing to do is write fresh code with similar behavior, rather than figure out how to extract the overlapping functionality. But as soon as someone has to read and understand the code and they come across duplicate blocks, they are faced with a dilemma. Code that might have made sense suddenly has to be understood. How is one section different from the other? How are they the same? Under what conditions is one section called? When do we call the other? You might argue that you're the only one reading your code, but if you don't touch that code for eight months it will be as incomprehensible to you as to a fresh coder. When we're trying to read two similar pieces of code, we have to understand why they're different, as well as how they're different. This wastes the reader's time; code should always be written to be readable first. I once had to try to understand someone's code that had three identical copies of the same three hundred lines of very poorly written code. I had been working with the code for a month before I realized that the three "identical" versions were actually performing slightly different tax calculations. Some of the subtle differences were intentional, but there were also obvious areas where someone had updated a calculation in one function without updating the other two. The number of subtle, incomprehensible bugs in the code could not be counted. Reading such duplicate code can be tiresome, but code maintenance is an even greater torment. As the preceding story suggests, keeping two similar pieces of code up to date can be a nightmare. We have to remember to update both sections whenever we update one of them, and we have to remember how the multiple sections differ so we can modify our changes when we are editing each of them. If we forget to update both sections, we will end up with extremely annoying bugs that usually manifest themselves as, "but I fixed that already, why is it still happening?" The result is that people who are reading or maintaining our code have to spend astronomical amounts of time understanding and testing it compared to if we had written the code in a non-repetitive manner in the first place. It's even more frustrating when we are the ones doing the maintenance. The time we save by copy-pasting existing code is lost the very first time we have to maintain it. Code is both read and maintained many more times and much more often than it is written. Comprehensible code should always be paramount. This is why programmers, especially Python programmers (who tend to value elegant code more than average), follow what is known as the Don't Repeat Yourself, or DRY principle. DRY code is maintainable code. My advice to beginning programmers is to never use the copy and paste feature of their editor. To intermediate programmers, I suggest they think thrice before they hit Ctrl + C. But what should we do instead of code duplication? The simplest solution is often to move the code into a function that accepts parameters to account for whatever sections are different. This isn't a terribly object-oriented solution, but it is frequently sufficient. For example, if we have two pieces of code that unzip a ZIP file into two different directories, we can easily write a function that accepts a parameter for the directory to which it should be unzipped instead. This may make the function itself slightly more difficult to read, but a good function name and docstring can easily make up for that, and any code that invokes the function will be easier to read. That's certainly enough theory! The moral of the story is: always make the effort to refactor your code to be easier to read instead of writing bad code that is only easier to write.
Read more
  • 0
  • 0
  • 3499

article-image-python-3-when-use-object-oriented-programming
Packt
12 Aug 2010
11 min read
Save for later

Python 3: When to Use Object-oriented Programming

Packt
12 Aug 2010
11 min read
(For more resources on Python 3, see here.) Treat objects as objects This may seem obvious, but you should generally give separate objects in your problem domain a special class in your code. The process is generally to identify objects in the problem and then model their data and behaviors. Identifying objects is a very important task in object-oriented analysis and programming. But it isn't always as easy as counting the nouns in a short paragraph, as we've been doing. Remember, objects are things that have both data and behavior. If we are working with only data, we are often better off storing it in a list, set, dictionary, or some other Python data structure. On the other hand, if we are working with only behavior, with no stored data, a simple function is more suitable. An object, however, has both data and behavior. Most Python programmers use built-in data structures unless (or until) there is an obvious need to define a class. This is a good thing; there is no reason to add an extra level of abstraction if it doesn't help organize our code. Sometimes, though, the "obvious" need is not so obvious. A Python programmer often starts by storing data in a few variables. As our program expands, we will later find that we are passing the same set of related variables to different functions. This is the time to think about grouping both variables and functions into a class. If we are designing a program to model polygons in two-dimensional space, we might start with each polygon being represented as a list of points. The points would be modeled as two-tuples (x,y) describing where that point is located. This is all data, stored in two nested data structures (specifically, a list of tuples): square = [(1,1), (1,2), (2,2), (2,1)] Now, if we want to calculate the distance around the perimeter of the polygon, we simply need to sum the distances between the two points, but to do that, we need a function to calculate the distance between two points. Here are two such functions: import mathdef distance(p1, p2): return math.sqrt((p1[0]-p2[0])**2 + (p1[1]-p2[1])**2)def perimeter(polygon): perimeter = 0 points = polygon + [polygon[0]] for i in range(len(polygon)): perimeter += distance(points[i], points[i+1]) return perimeter Now, as object-oriented programmers, we clearly recognize that a polygon class could encapsulate the list of points (data) and the perimeter function (behavior). Further, a point class, might encapsulate the x and y coordinates and the distance method. But should we do this? For the previous code, maybe, maybe not. We've been studying object-oriented principles long enough that we can now write the object-oriented version in record time: import mathclass Point: def __init__(self, x, y): self.x = x self.y = y def distance(self, p2): return math.sqrt((self.x-p2.x)**2 + (self.y-p2.y)**2)class Polygon: def __init__(self): self.vertices = [] def add_point(self, point): self.vertices.append((point))def perimeter(self): perimeter = 0 points = self.vertices + [self.vertices[0]] for i in range(len(self.vertices)): perimeter += points[i].distance(points[i+1]) return perimeter Now, to understand the difference a little better, let's compare the two APIs in use. Here's how to calculate the perimeter of a square using the object-oriented code: >>> square = Polygon()>>> square.add_point(Point(1,1))>>> square.add_point(Point(1,2))>>> square.add_point(Point(2,2))>>> square.add_point(Point(2,1))>>> square.perimeter()4.0 That's fairly succinct and easy to read, you might think, but let's compare it to the function-based code: >>> square = [(1,1), (1,2), (2,2), (2,1)]>>> perimeter(square)4.0 Hmm, maybe the object-oriented API isn't so compact! On the other hand, I'd argue that it was easier to read than the function example: How do we know what the list of tuples is supposed to represent in the second version? How do we remember what kind of object (a list of two-tuples? That's not intuitive!) we're supposed to pass into the perimeter function? We would need a lot of external documentation to explain how these functions should be used. In contrast, the object-oriented code is relatively self documenting, we just have to look at the list of methods and their parameters to know what the object does and how to use it. By the time we wrote all the documentation for the functional version, it would probably be longer than the object-oriented code. Besides, code length is a horrible indicator of code complexity. Some programmers (thankfully, not many of them are Python coders) get hung up on complicated, "one liners", that do incredible amounts of work in one line of code. One line of code that even the original author isn't able to read the next day, that is. Always focus on making your code easier to read and easier to use, not shorter. As a quick exercise, can you think of any ways to make the object-oriented Polygon as easy to use as the functional implementation? Pause a moment and think about it. Really, all we have to do is alter our Polygon API so that it can be constructed with multiple points. Let's give it an initializer that accepts a list of Point objects. In fact, let's allow it to accept tuples too, and we can construct the Point objects ourselves, if needed: def __init__(self, points = []): self.vertices = [] for point in points: if isinstance(point, tuple): point = Point(*point) self.vertices.append(point) This example simply goes through the list and ensures that any tuples are converted to points. If the object is not a tuple, we leave it as is, assuming that it is either a Point already, or an unknown duck typed object that can act like a Point. As we can see, it's not always easy to identify when an object should really be represented as a self-defined class. If we have new functions that accept a polygon argument, such as area(polygon) or point_in_polygon(polygon, x, y), the benefits of the object-oriented code become increasingly obvious. Likewise, if we add other attributes to the polygon, such as color or texture, it makes more and more sense to encapsulate that data into a class. The distinction is a design decision, but in general, the more complicated a set of data is, the more likely it is to have functions specific to that data, and the more useful it is to use a class with attributes and methods instead. When making this decision, it also pays to consider how the class will be used. If we're only trying to calculate the perimeter of one polygon in the context of a much greater problem, using a function will probably be quickest to code and easiest to use "one time only". On the other hand, if our program needs to manipulate numerous polygons in a wide variety of ways (calculate perimeter, area, intersection with other polygons, and more), we have most certainly identified an object; one that needs to be extremely versatile. Pay additional attention to the interaction between objects. Look for inheritance relationships; inheritance is impossible to model elegantly without classes, so make sure to use them. Composition can, technically, be modeled using only data structures; for example, we can have a list of dictionaries holding tuple values, but it is often less complicated to create an object, especially if there is behavior associated with the data. Don't rush to use an object just because you can use an object, but never neglect to create a class when you need to use a class. Using properties to add behavior to class data Python is very good at blurring distinctions; it doesn't exactly help us to "think outside the box". Rather, it teaches us that the box is in our own head; "there is no box". Before we get into the details, let's discuss some bad object-oriented theory. Many object-oriented languages (Java is the most guilty) teach us to never access attributes directly. They teach us to write attribute access like this: class Color: def __init__(self, rgb_value, name): self._rgb_value = rgb_value self._name = name def set_name(self, name): self._name = name def get_name(self): return self._name The variables are prefixed with an underscore to suggest that they are private (in other languages it would actually force them to be private). Then the get and set methods provide access to each variable. This class would be used in practice as follows: >>> c = Color("#ff0000", "bright red")>>> c.get_name()'bright red'>>> c.set_name("red")>>> c.get_name()'red' This is not nearly as readable as the direct access version that Python favors: class Color: def __init__(self, rgb_value, name): self.rgb_value = rgb_value self.name = namec = Color("#ff0000", "bright red")print(c.name)c.name = "red" So why would anyone recommend the method-based syntax? Their reasoning is that someday we may want to add extra code when a value is set or retrieved. For example, we could decide to cache a value and return the cached value, or we might want to validate that the value is a suitable input. In code, we could decide to change the set_name() method as follows: def set_name(self, name): if not name: raise Exception("Invalid Name") self._name = name Now, in Java and similar languages, if we had written our original code to do direct attribute access, and then later changed it to a method like the above, we'd have a problem: Anyone who had written code that accessed the attribute directly would now have to access the method; if they don't change the access style, their code will be broken. The mantra in these languages is that we should never make public members private. This doesn't make much sense in Python since there isn't any concept of private members! Indeed, the situation in Python is much better. We can use the Python property keyword to make methods look like a class attribute. If we originally wrote our code to use direct member access, we can later add methods to get and set the name without changing the interface. Let's see how it looks: class Color: def __init__(self, rgb_value, name): self.rgb_value = rgb_value self._name = name def _set_name(self, name): if not name: raise Exception("Invalid Name") self._name = name def _get_name(self): return self._namename = property(_get_name, _set_name) If we had started with the earlier non-method-based class, which set the name attribute directly, we could later change the code to look like the above. We first change the name attribute into a (semi-) private _name attribute. Then we add two more (semi-) private methods to get and set that variable, doing our validation when we set it. Finally, we have the property declaration at the bottom. This is the magic. It creates a new attribute on the Color class called name, which now replaces the previous name attribute. It sets this attribute to be a property, which calls the two methods we just created whenever the property is accessed or changed. This new version of the Color class can be used exactly the same way as the previous version, yet it now does validation when we set the name: >>> c = Color("#0000ff", "bright red")>>> print(c.name)bright red>>> c.name = "red">>> print(c.name)red>>> c.name = ""Traceback (most recent call last): File "<stdin>", line 1, in <module> File "setting_name_property.py", line 8, in _set_name raise Exception("Invalid Name")Exception: Invalid Name So if we'd previously written code to access the name attribute, and then changed it to use our property object, the previous code would still work, unless it was sending an empty property value, which is the behavior we wanted to forbid in the first place. Success! Bear in mind that even with the name property, the previous code is not 100% safe. People can still access the _name attribute directly and set it to an empty string if they wanted to. But if they access a variable we've explicitly marked with an underscore to suggest it is private, they're the ones that have to deal with the consequences, not us.
Read more
  • 0
  • 0
  • 14398

article-image-managing-it-portfolio-using-troux-enterprise-architecture
Packt
12 Aug 2010
16 min read
Save for later

Managing the IT Portfolio using Troux Enterprise Architecture

Packt
12 Aug 2010
16 min read
(For more resources on Troux, see here.) Managing the IT Portfolio using Troux Enterprise Architecture Almost every company today is totally dependent on IT for day-to-day operations. Large companies literally spend billions on IT-related personnel, software, equipment, and facilities. However, do business leaders really know what they get in return for these investments? Upper management knows that a successful business model depends on information technology. Whether the company is focused on delivery of services or development of products, management depends on its IT team to deliver solutions that meet or exceed customer expectations. However, even though companies continue to invest heavily in various technologies, for most companies, knowing the return-on-investment in technology is difficult or impossible. When upper management asks where the revenues are for the huge investments in software, servers, networks, and databases, few IT professionals are able to answer. There are questions that are almost impossible to answer without guessing, such as: Which IT projects in the portfolio of projects will actually generate revenue? What are we getting for spending millions on vendor software? When will our data center run out of capacity? This article will explore how IT professionals can be prepared when management asks the difficult questions. By being prepared, IT professionals can turn conversations with management about IT costs into discussions about the value IT provides. Using consolidated information about the majority of the IT portfolio, IT professionals can work with business leaders to select revenue-generating projects, decrease IT expenses, and develop realistic IT plans. The following sections will describe what IT professionals can do to be ready with accurate information in response to the most challenging questions business leaders might ask. Management repositories IT has done a fine job of delivering solutions for years. However, pressure to deliver business projects quickly has created a mentality in most IT organizations of "just put it in and we will go back and do the clean up later." This has led to a layering effect where older "legacy" technology remains in place, while new technology is adopted. With this complex mix of legacy solutions and emerging technology, business leaders have a hard time understanding how everything fits together and what value is provided from IT investments. Gone are the days when the Chief Information Officer (CIO) could say "just trust me" when business people asked questions about IT spending. In addition, new requirements for corporate compliance combined with the expanding use of web-based solutions makes managing technology more difficult than ever. With the advent of Software-as-a-Service (SaaS) or cloud computing, the technical footprint, or ecosystem, of IT has extended beyond the enterprise itself. Virtualization of platforms and service-orientation adds to the mind-numbing mix of technologies available to IT. However, there are many systems available to help companies manage their technological portfolio. Unfortunately, multiple teams within the business and within IT see the problem of managing the IT portfolio differently. In many companies, there is no centralized effort to gather and store IT portfolio information. Teams with a need for IT asset information tend to purchase or build a repository specific to their area of responsibility. Some examples of these include: Business goals repository Change management database Configuration management database Business process management database Fixed assets database Metadata repository Project portfolio management database Service catalog Service registry While each of these repositories provides valuable information about IT portfolios, they are each optimized to meet a specific set of requirements. The following table shows the main types of information stored in each of these repositories along with a brief statement about its functional purpose: Repository Main content Main purpose Business goals Goal statements and assignments Documents business goals and who is responsible Change management database Change request tickets, application owners Captures change requests and who can authorize change Configuration management database Identifies actual hardware and software in use across the enterprise Supports Information Technology Infrastructure Library (ITIL) processes Business process management database Business processes, information flows, and process owners Used to develop applications and document business processes Fixed assets database Asset identifiers for hardware and software, asset life, purchase cost, and depreciation amounts Documents cost and depreciable life of IT assets Metadata repository Data about the company databases and files Documents the names, definitions, data types, and locations of the company data Project portfolio management database Project names, classifications, assignments, business value and scope Used to manage IT workload and assess value of IT projects to the business Service catalog Defines hardware and compatible software available for project use Used to manage hardware and software implementations assigned to the IT department Service registry Names and details of reusable software services Used to manage, control, and report on reusable software It is easy to see that while each of these repositories serves a specific purpose, none supports an overarching view across the others. For example, one might ask: How many SQL Server databases do we have installed and what hardware do they run on? To answer this question, IT managers would have to extract data from the metadata repository and combine it with data from the Configuration Management Database (CMDB). The question could be extended: How much will it cost in early expense write-offs if we retire the SQL Server DB servers into a new virtual grid of servers? To answer this question, IT managers need to determine not only how many servers host SQL Server, but how old they are, what they cost at purchase time, and how much depreciation is left on them. Now the query must span at least three systems (CMDB, fixed assets, and metadata repository). The accuracy of the answer will also depend on the relative validity of the data in each repository. There could be overlapping data in some, and outright errors in others. Changing the conversation When upper management asks difficult questions, they are usually interested in cost, risk management, or IT agility. Not knowing a great deal about IT, they are curious about why they need to spend millions on technology and what they get for their investments. The conversation ends up being primarily about cost and how to reduce expenses. This is not a good position to be in if you are running a support function like Enterprise Architecture. How can you explain IT investments in a way that management can understand? If you are not prepared with facts, management has no choice but to assume that costs are out of control and they can be reduced, usually by dramatic amounts. As a good corporate citizen, it is your job to help reduce costs. Like everyone in management, getting the most out of the company's assets is your responsibility. However, as we in IT know, it's just as important to be ready for changes in technology and to be on top of technology trends. As technology leaders, it is our job to help the company stay current through investments that may pay off in the future rather than show an immediate return. The following diagram shows various management functions and technologies that are used to manage the business of IT: The dimensions of these tools and processes span systems that run the business to change the business and from the ones using operational information to using strategic information. Various technologies that support data about IT assets are shown. These include: Business process analytics and management information Service-oriented architecture governance Asset-liability management Information technology systems management Financial management information Project portfolio and management information The key to changing the conversation about IT is having the ability to bring the information of these disciplines into a single view. The single view provides the ability to actually discuss IT in a strategic way. Gathering data and reporting on the actual metrics of IT, in a way business leaders can understand, supports strategic planning. The strategic planning process combined with fact-based metrics establishes credibility with upper management and promotes improved decision making on a daily basis. Troux Technologies Solving the IT-business communication problem has been difficult until recently. Troux Technologies (www.troux.com) developed a new open-architected repository and software solution, called the Troux Transformation Platform, to help IT manage the vast array of technology deployed within the company. Troux customers use the suite of applications and advanced integration platform within the product architecture to deliver bottom-line results. By locating where IT expenses are redundant, or out-of-step with business strategy, Troux customers experience significant cost savings. When used properly, the platform also supports improved IT efficiency, quicker response to business requirements, and IT risk reduction. In today's globally-connected markets, where shocks and innovations happen at an unprecedented rate, antiquated approaches to Strategic IT Planning and Enterprise Architecture have become a major obstruction. The inability of IT to plan effectively has driven business leaders to seek solutions available outside the enterprise. Using SaaS or Application Service Providers (ASPs) to meet urgent business objectives can be an effective means to meet short-term goals. However, to be complete, even these solutions usually require integration with internal systems. IT finds itself dealing with unspecified service-level requirements, developing integration architectures, and cleaning up after poorly planned activities by business leaders who don't understand what capabilities exist within the software running inside the company. A global leader in Strategic IT Planning and Enterprise Architecture software, Troux has created an Enterprise Architecture repository that IT can use to put itself at the center of strategic planning. Troux has been successful in implementing its repository at a number of companies. A partial list of Troux's customers can be found on the website. There are other enterprise-level repository vendors on the market. However, leading analysts, such as The Gartner Group and Forrester Research, have published recent studies ranking Troux as a leader in the IT strategy planning tools space. Troux Transformation Platform Troux's sophisticated integration and collaboration capabilities support multiple business initiatives such as handling mergers, aligning business and IT plans, and consolidating IT assets. The business-driven platform provides new levels of visibility into the complex web of IT resources, programs, and business strategy so the business can see instantly where IT spending and programs are redundant or out-of-step with business strategy. The business suite of applications helps IT to plan and execute faster with data assimilated from various trusted sources within the company. The platform provides information necessary to relevant stakeholders such as Business Analysts, Enterprise Architects, The Program Management Office, Solutions Architects, and executives within the business and IT. The transformation platform is not only designed to address today's urgent cost-restructuring agendas, but it also introduces an ongoing IT management discipline, allowing EA and business users to drive strategic growth initiatives. The integration platform provides visibility and control to: Uncover and fix business/IT disconnects: This shows how IT directly supports business strategies and capabilities, and ensures that mismatched spending can be eliminated. Troux Alignment helps IT think like a CFO and demonstrate control and business purpose for the billions that are spent on IT assets, by ensuring that all stakeholders have valid and relevant IT information. Identify and eliminate redundant IT spending: This uncovers the many untapped opportunities with Troux Optimization to free up needless spend, and apply it either to the bottom line or to support new business initiatives. Speed business response and simplify IT: This speeds the creation and deployment of a set of standard, reusable building blocks that are proven to work in agile business cycles. Troux Standards enables the use of IT standards in real time, thereby streamlining the process of IT governance. Accelerate business transformation for government agencies: This helps federal agencies create an actionable Enterprise Architecture and comply with constantly changing mandates. Troux eaGov automatically identifies opportunities to reduce costs to business and IT risks, while fostering effective initiative planning and execution within or across agencies. Support EA methodology: Companies adopting The Open Group Architecture Framework (TOGAF™) can use the Troux for TOGAF solution to streamline their efforts. Unlock the full potential of IT portfolio investment: Unifies Strategic IT Planning, EA, and portfolio project management through a common IT governance process. The Troux CA Clarity Connection enables the first bi-directional integration in the market between CA Clarity Project Portfolio Management (PPM) and the Troux EA repository for enhanced IT investment portfolio planning, analysis, and control. Understand your deployed IT assets: Using the out-of-the-box connection to HP's Universal Configuration Management Database (uCMDB), link software and hardware with the applications they support. All of these capabilities are enabled through an open-architected platform that provides uncomplicated data integration tools. The platform provides Architecture-modeling capabilities for IT Architects, an extensible database schema (or meta-model), and integration interfaces that are simple to automate and bring online with minimal programming efforts. Enterprise Architecture repository The Troux Transformation Platform acts as the consolidation point across all the various IT management databases and even some management systems outside the control of IT. By collecting data from across various areas, new insights are possible, leading to reductions in operating costs and improvements in service levels to the business. While it is possible to combine these using other products on the market or even develop a home-grown EA repository, Troux has created a very easy-to-use API for data collection purposes. In addition, Troux provides a database meta-model for the repository that is extensible. Meta-model extensibility makes the product adaptable to the other management systems across the company. Troux also supports a configurable user interface allowing for a customized view into the repository. This capability makes the catalog appear as if it were a part of the other control systems already in place at the company. Additionally, Troux provides an optional set of applications that support a variety of roles, out of the box, with no meta-model extensions or user interface configurations required. These include: Troux Standards: This application supports the IT technology standards and lifecycle governance process usually conducted by the Enterprise Architecture department. Troux Optimization: This application supports the Application portfolio lifecycle management process conducted by the Enterprise Program Management Office (EPMO) and/or Enterprise Architecture. Troux Alignment: This application supports the business and IT assets and application-planning processes conducted by IT Engineering, Corporate Finance, and Enterprise Architecture. Even these three applications that are available out-of-the-box from Troux can be customized by extending their underlying meta-models and customizing the user interface. The EA repository provides output that is viewable online. Standard reports are provided or custom reports can be developed as per the specific needs of the user community. Departments within or even outside of IT can use the customized views, standard reports, and custom reports to perform analyses. For example, the Enterprise Program Management Office (EPMO) can produce reports that link projects with business goals. The EPMO can review the project portfolio of the company to identify projects that do not support company goals. Decisions can be made about these projects, thereby stopping them, slowing them down, or completing them faster. Resources can be moved from the stopped or completed low-value projects to the higher-value projects, leading to increased revenue or reduced costs for the company. In a similar fashion, the Internal Audit department can check on the level of compliance to company IT standards or use the list of applications stored within the catalog to determine the best audit schedule to follow. Less time can be spent auditing applications with minimal impact on company operations or on applications and projects targeted as low value. Application development can use data from the catalog to understand the current capabilities of the existing applications of the company. As staff changes or "off-shore" resources are applied to projects, knowing what existing systems do in advance of a new project can save many hours of work. Information can be extracted from the EA repository directly into requirements documentation, which is always the starting point for new applications, as well as maintenance projects on existing applications. One study performed at a major financial services company showed that over 40% of project development time was spent in the upfront work of documenting and explaining current application capabilities to business sponsors of projects. By supplying development teams with lists of application capabilities early in the project life cycle, time to gather and document requirements can be reduced significantly. Of course, one of the biggest benefactors of the repository is the EA group. In most companies, EA's main charter is to be the steward of information about applications, databases, hardware, software, and network architecture. EA can perform analyses using the data from the repository leading to recommendations for changes by middle and upper management. In addition, EA is responsible for collecting, setting, and managing the IT standards for the company. The repository supports a single source for IT standards, whether they are internal or external standards. The standards portion of the repository can be used as the centerpiece of IT governance. The function of the Architecture Review Board (ARB) is fully supported by Troux Standards. Capacity Planning and IT Engineering functions will also gain substantially through the use of an EA repository. The useful life of IT assets can be analyzed to create a master plan for technical refresh or reengineering efforts. The annual spend on IT expenses can be reduced dramatically through increased levels of virtualization of IT assets, consolidation of platforms, and even consolidation of whole data centers. IT Engineering can review what is currently running across the company and recommend changes to reduce software maintenance costs, eliminate underutilized hardware, and consolidate federated databases. Lastly, IT Operations can benefit from a consolidated view into the technical footprint running at any point in time. Even when system availability service levels call for near-real-time error correction, it may take hours for IT Operations personnel to diagnose problems. They tend not to have a full understanding of what applications run on what servers, which firewalls support which networks, and which databases support which applications. Problem determination time can be reduced by providing accurate technical architecture information to those focused on keeping systems running and meeting business service-level requirements. Summary This article identified the problem IT has with understanding what technologies it has under management. While many solutions are in place in many companies to gain a better view into the IT portfolio, none are designed to show the impact of IT assets in the aggregate. Without the capabilities provided by an EA repository, IT management has a difficult time answering tough questions asked by business leaders. Troux Technologies offers a solution to this problem using the Troux Transformation Platform. The platform acts as a master metadata repository and becomes the focus of many efforts that IT may run to reduce significant costs and improve business service levels. Further resources on this subject: Troux Enterprise Architecture: Managing the EA function [article]
Read more
  • 0
  • 0
  • 4701
Unlock access to the largest independent learning library in Tech for FREE!
Get unlimited access to 7500+ expert-authored eBooks and video courses covering every tech area you can think of.
Renews at €14.99/month. Cancel anytime
article-image-planning-and-preparing-oracle-siebel-crm-installation
Packt
10 Aug 2010
5 min read
Save for later

Planning and Preparing the Oracle Siebel CRM Installation

Packt
10 Aug 2010
5 min read
(For more resources on Oracle, see here.) The overall process of planning and preparation can be described as follows. The following flowchart describes the major steps of the process of planning and preparing a Siebel CRM installation. In this article, we will describe each step in detail. Planning the Siebel CRM installation Implementing Siebel CRM for thousands of users in corporations that do business across the globe is not something a single person would do on a single day. Sometimes, hundreds of technicians, IT architects and business analysts are involved to fulfil the company's requirements. Siebel CRM projects can be costly, lengthy, and sometimes risky expeditions into rough terrain. In a typical Siebel CRM project, people from various companies—integrators and IT staff of the customer—work together to install and set up the different Siebel environments from first prototyping areas over the development, test, and training environments, to the final production environment. Siebel and third-party software for these environments are typically installed on multiple server machines and it is not unusual to find a mix of operating systems. What is expected from us—being the reliable and trustworthy expert that the customer hired to install Siebel CRM on their systems—is a planning document. The key to a useful planning document is knowledge about the customer's IT infrastructure, as well as the Siebel installation and configuration processes. The following is an example of a typical planning document that provides all the information that is needed to successfully install the Siebel CRM infrastructure on Microsoft Windows machines. The official Siebel Installation Guide includes a Deployment Planning Worksheet, which can serve as a starting point. In a real life project, we can use any spreadsheet application to create and collaborate on this information. Sample planning document The following table is a sample planning document for information regarding the relational database management system (RDBMS) to host the Siebel database. We record information about the RDBMS vendor and version as well as the machine hostname and administrative user account. For a typical Siebel CRM installation, we also plan the creation of two tablespaces. Details on how to create tablespaces and undertake other prerequisite installation steps are described later in this article. Component/Parameter Name/Value Examples Description Database Server Vendor Oracle   Database Server Version 11gR1   DB Server System Account/Password sys/T67PBhtr as SYSDBA Needed to connect directly to the database to run the grantusr.sql script. Database Server hostname dbsrvr1   DB host admin user Administrator   DB host admin user password XBXfi8F9 See the note on password examples. Database Server port 1521   Database Server SID ORCL   Siebel DB index tablespace SIEBELDB_IDX This tablespace will hold the indexes of the Siebel CRM schema. Siebel DB data tablespace SIEBELDB_DATA This tablespace will hold the data tables of the Siebel CRM schema. More planning information Of course, a decent planning document contains more than just a series of tables. Sometimes, we might need to bring specialists on board to define the necessary amount of servers, the hardware configuration, and so forth. Security-related information such as user accounts, remote access settings, or simply the phone numbers of the firewall administrators, can help the project team to finish a Siebel CRM infrastructure provisioning on time. Certainly, the project plan will include a timeline. We will not go into details of project management, but we should ensure that our project plan provides enough time and money for training—for both technicians and the end user community. Understanding hardware and software prerequisites Many problems in Siebel CRM projects arise from improper planning. As we learned, delivering a decent planning document is a key milestone of our Siebel CRM implementation project. Therefore, it is very important that any person involved in planning and conducting a Siebel CRM installation has access to the Siebel System Requirements and Supported Platforms document that can be downloaded from the Oracle Technology Network website: http://download.oracle.com/docs/cd/E11886_01/srsphomepage.html. This document is available for each individual Siebel CRM version and outlines in detail the minimum hardware requirements and software prerequisites. For example, if we plan to provide a prototype environment for evaluation and testing of Siebel CRM 8.1 and would like to use Microsoft Windows Server 2003 as the operating system, we would have to provision hardware and software as follows: Siebel Component Minimum Processor Requirements Minimum Memory Requirements Siebel Server 2 PIII XEON 500 MHz 1 GB Siebel Gateway Name Server PIII XEON 500 MHz 256 MB Web Server PIII XEON 500 MHz 512 MB If we were to install these components on a single piece of hardware, we would have to provision a 4 CPU unit (2 for the Siebel Server, 1 for the Siebel Gateway Name Server, and 1 for the Web Server) with at least 1.7 GB (1 GB plus 256 MB + 512 MB) of free memory for the Siebel components, which would be a physical minimum of 2 GB of memory as the operating system will also be hungry for memory. Sizing the Siebel deployment Installing Siebel CRM for personal evaluation or prototyping is one thing, providing a stable and high performing enterprise application to hundreds or thousands of end users is quite another challenge. In certain phases of the Siebel CRM implementation project, consultants and IT staff will have to deliver a sizing document that provides insight into the expected number of end users and their concurrent sessions. The necessary amount of hardware units and software components is dependent on these main factors: Maximum number of concurrent user sessions Expected volume of data and indexes Hardware vendor Operating system type Database vendor Network bandwidth High-availability and failover requirements Each of these has to be considered and evaluated. Customers typically rely on the services of experienced staff from either Oracle or consulting corporations to accomplish this.
Read more
  • 0
  • 0
  • 2649

article-image-managing-user-accounts-oracle-siebel-crm-8
Packt
06 Aug 2010
5 min read
Save for later

Managing User Accounts in Oracle Siebel CRM 8

Packt
06 Aug 2010
5 min read
Understanding divisions and organizations Mapping real world entities to technical concepts is one of the key factors for successful software products. It is therefore quite interesting to see how the Siebel design team faced the challenge of bringing the complex hierarchical relationships of large corporations into the Siebel data model. Early in the analysis phase of a Siebel CRM implementation project, the divisional or departmental hierarchy of the customer is analyzed and documented. The typical diagram type to document the divisions of a company is an organization chart. The following is the organization chart for an example company: The Sales, Service, and Marketing divisions are subordinate to the Headquarter division. The Sales department has subdivisions, which define the territories (North and South) that the sales force operates in. Setting up divisions Once the divisional hierarchy of a company is documented, it must be translated to Siebel administrative data. An administrator uses the Administration - Group screen, Internal Divisions view—shown in the following screenshot—to enter and manage the division information: This view allows administrators to enter and maintain information about a company's divisions. The example company visible in the screenshot (Vision Corporation) is part of the Siebel sample database and has four subordinate divisions. In order to create a new divisional hierarchy, we can follow the steps in the task list below: Log in to the Siebel application using an administrative user account. Navigate to the Administration - Group screen, Internal Divisions view. Create a new record for the top-level division first. Enter address and other information if required. Save the division record. Create a new division for each subordinate division and use the Parent Division field to select the appropriate parent division. Use the explorer applet to verify that the divisional hierarchy represents the organization chart. The following screenshot shows the explorer applet in the Internal Divisions view after the entry of the data from the example organization chart: In order to distinguish the example company from other divisions in the database, the acronym "AHA " was used. From an administrative perspective, we must be aware of the fact that organizational changes might occur frequently. These changes can include one department becoming subordinate of another, or other departments being detached from the hierarchy in order to become separate companies. Siebel administrators must be informed of these changes in order to be able to adjust the division data in a timely manner. In your demonstration environment, use the instructions in the above section to create a division hierarchy. You might want to use the example or create your own divisions. Setting up organizations When a division or an entire partner company wants to use the Siebel CRM infrastructure, this is typically accompanied by the requirement to associate data with the division or partner company in order to provide data security. Siebel administrators can declare a division as an organization. This is done by simply checking the Organization Flag of a division. However, this change cannot be undone. Once the division is flagged as an organization and the record is saved, the flag becomes read only, as shown in the following screenshot: We can decide which divisions within the organization chart should be flagged as organizations depending on the data security requirements defined by the project team. The result is typically a second hierarchy of organizations within the division hierarchy. Once an organization is created, Siebel data such as customer accounts, service requests, and so on can be associated with the organization. The following diagram shows how the divisions named Headquarter and Sales have been flagged as organizations. They are now part of the organization hierarchy. By default, each new organization becomes subordinate to the "Default Organization", which the position of the Siebel Administrator (SADMIN) is assigned to. If data security policies mandate, we must set the Parent Organization field to an empty value in the Organizations view of the Administration - Group screen. Even if a division cannot be associated to Siebel data, employees who have a position within that division are automatically associated with the nearest organization that can be located upwards in the division hierarchy. In the above example, an employee who has a position in the AHA Sales North division will be associated with the Sales organization. The following screenshot shows the AHA Sales North division (note that the Organization Flag is unchecked) in the Internal Divisions view: The Organization Name field displays the name of the nearest organization (AHA Sales) above the AHA Sales North division. Employees who are associated with a position in the AHA Sales North division will automatically be associated with the AHA Sales organization. They will therefore be able to see data associated with the AHA Sales organization and each record they create will be automatically associated with the AHA Sales organization. Similar to divisions, organizations cannot be deleted. When organizational changes require it, a Siebel administrator must detach the non-existing organization or division from all parent records by emptying the parent division field and change the name to indicate the state of the organization or division. For example, the name can be prefixed with "NOT USED" to indicate that the division or organization no longer exists. Furthermore, records that are associated with an organization that no longer exists must be re-assigned to other organizations. This is typically achieved by using the Siebel Assignment Manager. Mark at least one of the sample divisions you created earlier as an organization by setting the Organization Flag and saving the record.
Read more
  • 0
  • 0
  • 2951

article-image-coldfusion-9-power-cfcs-and-web-forms
Packt
05 Aug 2010
13 min read
Save for later

ColdFusion 9: Power CFCs and Web Forms

Packt
05 Aug 2010
13 min read
(For more resources on ColdFusion, see here.) There used to be long pages of what we called "spaghetti code" because the page would go on and on. You had to follow the conditional logic by going through the page up and down, and then had to understand how things worked. This made writing, updating, and debugging a diffcult task even for highly-skilled developers CFCs allow you to encapsulate some part of the logic of a page inside an object. Encapsulation simply means packaged for reuse inside something. CFCs are the object-packaging method used in ColdFusion. The practice of protecting access In CFC methods, there is an attribute called "access".Some methods within a CFC are more examples of reuse. The sample code for _product.cfc is shown here. It is an example of a power CFC. There is a method inside the CFC called setDefaults(). The variable variables.field.names comes from another location in our CFC: <cffunction name="setDefaults" access="private" output="false"> <cfset var iAttr = 0> <cfloop list="#listLen(variables.field.names)#" index="iAttr"> <cfscript> variables.attribute[#listGetAt(variables.field.names,iAttr)#] = setDefault(variables.field.names,iAttr); </cfscript> </cfloop></cffunction> The logic for this would actually be used in more than one place inside the object. When the object is created during the first run, it would call the setDefaults() method and set the defaults. When you use the load method to insert another record inside the CFC, it will run this method. This will become simpler as you use CFCs and methods more often. This is a concept called refactoring, where we take common features and wrap them for reuse. This takes place even inside a CFC. Again, the setDefaults() function is just another method inside the same CFC. Now, we look at the access attribute in the code example and note that it is set to private. This means that only this object can call the method. One of the benefits to CFCs is making code simpler. The interface to the outside world of the CFC is its methods. We can hide a method from the outside world, and also protect access to the method by setting the access attribute to private. If you want to make sure that only CFCs in the same directory can access these CFC's methods, then you will have to set the attribute to package. This is a value that is rarely used. The default value for the access attribute is public. This means that any code running on the web server can access the CFC. (Shared hosting companies block one account from being able to see the other accounts on the same server. If you are concerned about your hosting company, then you should either ask them about this issue or move to a dedicated or virtual hosting server.) The last value for the access attribute is remote. This is actually how you create a number of "cool power" uses of the CFC. There is a technology on the Web called web services. Setting the CFC to remote allows access to the CFC as a web service. You can also connect to this CFC through Flash applications, Flex, or AIR, using the remote access value. This method also allows the CFC to respond to AJAX calls. Now, we will learn to use more of the local power features. Web forms introduction Here, we will discuss web forms along with CFCs. Let us view our web form page. Web forms are the same in ColdFusion as they are in any other HTML scenario. You might even note that there is very little use for web forms until you have a server-side technology such as ColdFusion. This is because when the form is posted, you need some sort of program to handle the data posted back to the server. <!--- Example: 3_1.cfm ---><!--- Processing ---><!--- Content ---><form action="3_1.cfm" method="post"> <table> <tr> <td>Name:</td> <td><input type="text" name="name" id="idName" value="" /></td> </tr> <tr> <td>Description:</td> <td><input type="text" name="description" id="idDescription" value="" /></td> </tr> <tr> <td>Price:</td> <td><input type="text" name="price" id="idPrice" value="" /></td> </tr> <tr> <td>&nbsp;</td> <td><input type="submit" name="submit" value="submit" /></td> </tr> </table></form> First, notice that all of the information on the page is in the content section. Anything that goes from the server to the browser is considered as content. You can fll in and submit the form, and you will observe that all of the form fields get cleared out. This is because this form posts back to the same page. Self-posting forms are a valid method of handling page fow on websites. The reason why nothing seems to be happening is because the server is not doing anything with the data being sent back from the browser. Let us now add <cfdump var="#form#"/> to the bottom of the content, below the form tag, and observe what we get when we post the form: Now we see another common structure in ColdFusion. It is known as the form structure. There are two types of common structures that send data to the server. The first one is called get and the second one is called post. If you see the code, you will notice that the method of the form is post. The form post setting is the same as coding with the form variable in ColdFusion. You should also observe that there is one extra field in the form structure that is not shown in the URL structure variable. It is the FIELDNAMES variable. It returns a simple list of the field names that were returned with the form. Let us edit the code and change the form tag attribute to get. Then, refresh the page and click on the submit button: From the previous screenshot, it is evident that the browser looks at the get or post value of the form, and sends a get or post back to the server. Post is a "form method" belonging to the past and this is why ColdFusion translates posted variables to the form structure. Now change the dump tag to "URL" and observe the results. Fill out the form and submit it again with the new change. This displays the values in our structure as we would expect. This means you can either send URL-type data back to the server, or form-type data with forms. The advantage of sending form data is that form data can handle a larger volume of data being sent back to the server as compared to a get or URL request. Also, it is worth noting that this style of return prevents the form field values from being exposed in the URL. They can still be accessed, but are just not visible in the URL any more. So the method of choice for forms is post. Change both the method of the form attribute and the value of the cfdump var to form again. The Description box is not ideal for entering product descriptions. So, we are going to use a text area in its place. Use the following code to accommodate a text area box. You can change the size of form's objects using attributes and styles: <tr> <td>Description:</td> <td> <textArea name="description" id="idDescription"></textArea> </td></tr> Here, we see our form looking different. If you fill up the description with more content than the box can hold, it shows the scroll bars appropriately. Managing our product data Currently, we have a form that can be used for two purposes. It can be used to enter a new product as well as to edit existing ones. We are going to reuse this form. Reuse is the fastest path to make things easier. However, we must not think that it is the only way to do things. What we should think is that not reusing something requires a reason for doing it differently. In order to edit an existing product, we will have to create a page that shows the existing product records. Let us create the page: <!--- Example: product_list.cfm ---><!--- Processing ---><cfscript> objProduct = createObject("component","product").init(dsn="cfb"); rsProducts = objProduct.getRecordset();</cfscript><!--- Content ---><h3>Select a product to edit.</h3><ul> <cfoutput query="rsProducts"> <li> <a href="product_edit.cfm?id=#rsProducts.id#">#rsProducts.name# </li> </cfoutput></ul> There is no new code here. This is the browser view that we get when we run this page. Here, we will post our edit page. Before you run the code, take the code from 3_1.cfm that we wrote at the beginning of the article and save a copy as product_edit.cfm to make the page work correctly when someone clicks on any of the products: Now, we will click on a product. Let us manage the Watermelon Plant for now and observe what happens on the next page: This is our edit page, and we will modify it so that it can get the data when we click through from our list page. Getting data to our edit page The current page looks similar to the page where we put the form. To get the data from our database onto the page, we need to do a few things here. First, let us change the action of the form tag to product_edit.cfm. We can modify the processing section of the page frst, which will make things simpler. Add the following code to your product_edit.cfm page: <!--- Processing ---><cfparam name="url.id" default="0"><cfscript> objProduct = createObject("component","product").init(dsn="cfb"); objProduct.load(url.id);</cfscript> We need the default value set so that we do not receive an error message if the page is called without an id. After we set our default, we will see that we have created an object from our CFC object class. This time, we are passing the Data Source Name dsn into the object through the constructor method. This makes our code more portable, and ready for reuse. Once we have an instance, we set the current record using the load method and passing the id of the data record to the method. Let us look at the minor changes that we will make to the content section. We will add the values of the object's protected attributes. <!--- Content ---><cfoutput> <form action="product_edit.cfm" method="post"> <table> <tr> <td>Name:</td> <td> <input type="text" name="name" id="idName" value="#objProduct.get('name')#" /> </td> </tr> <tr> <td>Description:</td> <td> <textArea name="description" id="idDescription"> #objProduct.get('description')#</textArea> </td> </tr> <tr> <td>Price:</td> <td> <input type="text" name="price" id="idPrice" value="#objProduct.get('price')#" /> </td> </tr> <tr> <td>&nbsp;</td> <td> <input type="submit" name="submit" value="submit" /> </td> </tr> </table> </form></cfoutput> Now, we will refresh the form and see how the results differ: Doesn't this look better? We can go back to the list page and retrieve an existing product from the edit form. If we submit back the same form, browsers tend to empty out the form. It should not do that, but the form is not posting the ID of the record back to the server. This can lead to a problem because, if we do not send the ID of the record back, the database will have no idea as to which record's details should be changed. Let us solve these issues first, and then we will learn to use a new tag called the <cfinclude> tag along the way. The first problem that we are going to solve is where we are calling the page with the ID value in the URL structure; then, if we post the page we will be calling the page with the ID in the form structure. We are going to use a technique that has been widely used for years in the ColdFusion community. We are going to combine the two scopes into a new common structure. We will create a structure called attributes. First we will check if it exists. If it does not, then we will create the structure. After that, we will merge the URL structure, and then the FORM structure into the attributes structure. We will put that code in a common page called request_attributes.cfm, so we can include it on any page we want, reusing the code. Do remember that the form and URL scope always exist. <!--- request_attributes.cfm ---><cfscript> if(NOT isDefined("attributes")) { attributes = structNew(); } structAppend(attributes,url); structAppend(attributes,form);</cfscript> Let us modify our edit page in order to take care of a couple of issues. We need to include the script that we have just created. We will modify the processing section of our edit page as highlighted here: <!--- Processing ---><cfinclude template="request_attributes.cfm"><cfparam name="attributes.id" default="0"><cfscript> objProduct = createObject("component","product").init(dsn="cfb"); objProduct.load(attributes.id);</cfscript> There is only one more thing we need now: We need our form to store the id value of the record that is being managed. We could just put it in a textbox like the other fields, but the user does not need to know that information. Let us use a hidden input field and add it after our form tag: <!--- Content ---><cfoutput> <form action="product_edit.cfm" method="post"> <input type="hidden" name="id" value="#objProduct.get('id')#"> Refresh the screen, and it will work when we use the form, or when we choose an item from the product list page. We have now created our edit/add page.
Read more
  • 0
  • 0
  • 1817

article-image-setting-glassfish-jms-and-working-message-queues
Packt
30 Jul 2010
4 min read
Save for later

Setting up GlassFish for JMS and Working with Message Queues

Packt
30 Jul 2010
4 min read
(For more resources on Java, see here.) Setting up GlassFish for JMS Before we start writing code to take advantage of the JMS API, we need to configure some GlassFish resources. Specifically, we need to set up a JMS connection factory, a message queue, and a message topic. Setting up a JMS connection factory The easiest way to set up a JMS connection factory is via GlassFish's web console. The web console can be accessed by starting our domain, by entering the following command in the command line: asadmin start-domain domain1 Then point the browser to http://localhost:4848 and log in: A connection factory can be added by expanding the Resources node in the tree at the left-hand side of the web console, expanding the JMS Resources node and clicking on the Connection Factories node, then clicking on the New... button in the main area of the web console. For our purposes, we can take most of the defaults. The only thing we need to do is enter a Pool Name and pick a Resource Type for our connection factory. It is always a good idea to use a Pool Name starting with "jms/" when picking a name for JMS resources. This way JMS resources can be easily identified when browsing a JNDI tree. In the text field labeled Pool Name, enter jms/GlassFishBookConnectionFactory. Our code examples later in this article will use this JNDI name to obtain a reference to this connection factory. The Resource Type drop-down menu has three options: javax.jms.TopicConnectionFactory - used to create a connection factory that creates JMS topics for JMS clients using the pub/sub messaging domain javax.jms.QueueConnectionFactory - used to create a connection factory that creates JMS queues for JMS clients using the PTP messaging domain javax.jms.ConnectionFactory - used to create a connection factory that creates either JMS topics or JMS queues For our example, we will select javax.jms.ConnectionFactory. This way we can use the same connection factory for all our examples, those using the PTP messaging domain and those using the pub/sub messaging domain. After entering the Pool Name for our connection factory, selecting a connection factory type, and optionally entering a description for our connection factory, we must click on the OK button for the changes to take effect. We should then see our newly created connection factory listed in the main area of the GlassFish web console. Setting up a JMS message queue A JMS message queue can be added by expanding the Resources node in the tree at the left-hand side of the web console, expanding the JMS Resources node and clicking on the Destination Resources node, then clicking on the New... button in the main area of the web console. In our example, the JNDI name of the message queue is jms/GlassFishBookQueue. The resource type for message queues must be javax.jms.Queue. Additionally, a Physical Destination Name must be entered. In this example, we use GlassFishBookQueue as the value for this field. After clicking on the New... button, entering the appropriate information for our message queue, and clicking on the OK button, we should see the newly created queue: Setting up a JMS message topic Setting up a JMS message topic in GlassFish is very similar to setting up a message queue. In the GlassFish web console, expand the Resources node in the tree at the left hand side, then expand the JMS Resouces node and click on the Destination Resources node, then click on the New... button in the main area of the web console. Our examples will use a JNDI Name of jms/GlassFishBookTopic. As this is a message topic, Resource Type must be javax.jms.Topic. The Description field is optional. The Physical Destination Name property is required. For our example, we will use GlassFishBookTopic as the value for this property. After clicking on the OK button, we can see our newly created message topic: Now that we have set up a connection factory, a message queue, and a message topic, we are ready to start writing code using the JMS API.
Read more
  • 0
  • 0
  • 8796
article-image-ensuring-quality-unit-testing-microsoft-visual-studio-2010
Packt
29 Jul 2010
12 min read
Save for later

Ensuring Quality for Unit Testing with Microsoft Visual Studio 2010

Packt
29 Jul 2010
12 min read
(For more resources on Microsoft products, see here.) Change is not always good Any change to existing code means it has the potential to change the external behavior of the system. When we refactor code, we explicitly intend not to change the external behavior of system. But how do we perform our refactorings while being reasonably comfortable that we haven't changed external behavior? The first step to validating that external behavior hasn't been affected is to define the criteria by which we can validate that the external behavior hasn't changed. Automated testing Every developer does unit testing. Some developers write a bit of test code, maybe an independent project that uses the code to verify it in some way then promptly forgets about the project. Or even worse, they throw away that project. For the purposes of this text, when I use the term "testing", I mean "automated testing". Test automation is the practice of using a testing framework to facilitate and execute tests. A test automation framework promotes the automatic execution of multiple tests. Generally these frameworks include some sort of Graphical User Interface that helps manage tests and their execution. Passing tests are "Green" and failing tests are "Red", which is where the "Red, Green, Refactor" mantra comes from. Unit tests If we're refactoring, there's a chance that what we want to refactor isn't currently under test. This means that if we do perform refactoring on the code, we'll have to manually test the system through the established user interfaces to verify that the code works. Realistically, this doesn't verify the code; this verifies that the external behavior hasn't changed. There could very well be a hidden problem in the code that won't manifest itself until the external behavior has been modified—distancing detection of the defect from when it was created. Our goal is to not affect external behavior when refactoring, so verification through the graphical user interface doesn't fully verify our changes and is time consuming and more prone to human error. What we really want to do is unit test the code. The term "unit test" has become overloaded over the years. MSDN describes unit testing as taking: ... the smallest piece of testable software in the application, [isolating] from the remainder of the code, and [determining] whether it behaves exactly as [expected]. This smallest piece of software is generally at the method level—unit testing is effectively about ensuring each method behaves as expected. Originally, it meant to test an individual unit of code. "Unit test" has evolved to mean any sort of code-based automated test, tests that developers write and execute within the development process. With various available frameworks, the process of testing the graphical user interface can also be automated in a code-based test, but we won't focus on that. It's not unusual for some software projects to have hundreds and thousands of individual unit tests. Given the granularity of some of the tests, it's also not unusual for the lines of code in the unit tests to outnumber the actual production code. This is expected. At the lowest level, we want to perform true "unit-testing", we want to test individual units of code, independently, to verify that unit of code functions as expected—especially in the presence of refactoring. To independently test these units of code we often have to separate them from their dependant code. For example, if I want to verify the business logic to uniquely generate an entity ID, there's no real need for me to access the database to verify that code. That code to generate a unique ID may depend on a collection of IDs to fully verify the algorithm to generate a unique ID—but that collection of IDs, for the purposes of verification, doesn't need to come from a database. So, we want to separate out use of some dependencies like the database from some of our tests. Techniques for loosely-coupled design like Dependency Inversion and Dependency Injection allow for a composable design. This composable design aids in the flexibility and agility of our software system, but it also aids in unit testing. Other testing Useful and thorough information about all types of testing could easily reach enough information to take up several tomes. We're focusing on the developer task of refactoring, so we're limiting our coverage of testing to absolute essential developer testing: unit testing. The fact that we're focusing on unit tests with regard to refactoring doesn't mean that other types of testing is neither useful nor needed. The fact that developers are performing unit tests doesn't preclude that they also need to perform a certain level of integration testing and the QA personnel are performing other levels of integration testing, user interface testing, user acceptance testing, system testing, and so on. Integration testing is combining distinct modules in the system to verify that they interoperate exactly as expected. User interface testing is testing that the user interface is behaving exactly as expected. User acceptance testing is verifying that specific user requirements are being met—which could involve unit testing, integration testing, user interface testing, verifying non-functional requirements, and so on. Mocking Mocking is a general term that usually refers the substitution of Test Doubles for dependencies within a system under test that aren't the focus of the test. "Mocking" generally encompasses all types of test doubles, not just Mock test doubles. Test Double is any object that takes the place of a production object for testing purposes.Mock is a type of Test Double that stands in for a production object whose behavior or attributes are directly used within the code under test and within the verification. Test Doubles allow an automated test to gather the criteria by which the code is verified. Test Doubles allow isolation of the code under test. There are several different types of Test Doubles: Mock, Dummy, Stub, Fake, and Spy. Dummy is a type of Test Double that is only passed around within the test but not directly used by the test. "null" is an example of a dummy—use of "null" satisfies the code, but may not be necessary for verification. Stub is a type of Test Double that provides inputs to the test and may accept inputs from the test but does not use them. The inputs a Stub provides to the test are generally "canned". Fake is a type of Test Double that is used to substitute a production component for a test component. A Fake generally provides an alternate implementation of that production component that isn't suitable for production but useful for verification. Fakes are generally used for components with heavy integration dependencies that would otherwise make the test slow or heavily reliant on configuration. Spy is a type of Test Double that effectively records the actions performed on it. The recorded actions can then be used for verification. This is often used in behavioral-based—rather than state-based—testing. Test doubles can be created manually, or they can be created automatically through the use of mocking frameworks. Frameworks like Rhino Mocks provide the ability to automatically create test doubles. Mocking framework generally rely on a loosely-coupled design so that the generated test doubles can be substituted for other objects based upon an interface. Let's look at an example of writing a unit test in involving mocking. If we return to one of our decoupling examples—InvoiceRepository—we can now test the internals of InvoiceRepository without testing our Data Access Layer (DAL). We would start by creating a test for the InvoiceRepository.Load method: [TestClass()]public class InvoiceRepositoryTest{[TestMethod()]public void LoadTest(){ DateTime expectedDate = DateTime.Now; IDataAccess dataAccess = new InvoiceRepositoryDataAccessStub(expectedDate); InvoiceRepository target = new InvoiceRepository(dataAccess); Guid invoiceId = Guid.NewGuid(); Invoice actualInvoice = target.Load(invoiceId); Assert.AreEqual(expectedDate, actualInvoice.Date); Assert.AreEqual(invoiceId, actualInvoice.Id); Assert.AreEqual("Test", actualInvoice.Title); Assert.AreEqual(InvoiceStatus.Posted, actualInvoice.Status); Assert.AreEqual(1, actualInvoice.LineItems.Count()); InvoiceLineItem actualLineItem = actualInvoice.LineItems.First(); Assert.AreEqual("Description", actualLineItem.Description); Assert.AreEqual(1F, actualLineItem.Discount); Assert.AreEqual(2F, actualLineItem.Price); Assert.AreEqual(3F, actualLineItem.Quantity);}} Here, we're creating an instance of our repository passing it a Stub IDataAccess class. We then invoke the Load method and verify the various attributes of the resulting Invoice object. We, of course, don't have a class named InvoiceRepositoryDataAccesStub, so we'll have to create one. This class, for the purposes of this test, will look like this. class InvoiceRepositoryDataAccesStub : IDataAccess{ private DateTime constantDate; public InvoiceRepositoryDataAccesStub(DateTime date){ constantDate = date;} public System.Data.DataSet LoadInvoice(Guid invoiceId){ DataSet invoiceDataSet = new DataSet("Invoice"); DataTable invoiceTable = invoiceDataSet.Tables.Add("Invoices"); DataColumn column = new DataColumn("Id", typeof(Guid)); invoiceTable.Columns.Add(column); column = new DataColumn("Date", typeof(DateTime)); invoiceTable.Columns.Add(column); column = new DataColumn("Title", typeof(String)); invoiceTable.Columns.Add(column); column = new DataColumn("Status", typeof(int)); invoiceTable.Columns.Add(column); DataRow invoiceRow = invoiceTable.NewRow(); invoiceRow["Id"] = invoiceId; invoiceRow["Date"] = constantDate; invoiceRow["Status"] = InvoiceStatus.Posted; invoiceRow["Title"] = "Test"; invoiceTable.Rows.Add(invoiceRow); return invoiceDataSet;}public System.Data.DataSet LoadInvoiceLineItems(Guid invoiceId){ DataSet lineItemDataSet = new DataSet("LineItem"); DataTable lineItemTable = lineItemDataSet.Tables.Add("LineItems"); DataColumn column =new DataColumn("InvoiceId", typeof(Guid)); lineItemTable.Columns.Add(column); column = new DataColumn("Price", typeof(Decimal)); lineItemTable.Columns.Add(column); column = new DataColumn("Quantity", typeof(int)); lineItemTable.Columns.Add(column); column = new DataColumn("Discount", typeof(double)); lineItemTable.Columns.Add(column); column = new DataColumn("Description", typeof(String)); lineItemTable.Columns.Add(column); column = new DataColumn("TaxRate1", typeof(String)); lineItemTable.Columns.Add(column); column = new DataColumn("TaxRate2", typeof(String)); lineItemTable.Columns.Add(column); DataRow lineItemRow = lineItemDataSet.Tables["LineItems"].NewRow(); lineItemRow["InvoiceId"] = invoiceId; lineItemRow["Discount"] = 1F; lineItemRow["Price"] = 2F; lineItemRow["Quantity"] = 3; lineItemRow["Description"] = "Description"; lineItemTable.Rows.Add(lineItemRow); return lineItemDataSet;}public void SaveInvoice(System.Data.DataSet dataSet){ throw new NotImplementedException();}} Here, we're manually creating DataSet object and populating rows with canned data that we're specifically checking for in the validation code within the test. It's worth noting that we haven't implemented SaveInvoice in this class. This is mostly because we haven't implemented this in the production code yet; but, in the case of testing Load, an exception would be thrown should it call SaveInvoice— adding more depth to the validation of the Load method, since it shouldn't be using SaveInvoice to load data. In the InvoiceRepositoryTest.LoadTest method, we're specifically using the InvoiceRepositoryDataAccessStub. InvoiceRepositoryDataAccessStub is a Stub of and IDataAccess specifically for use with InvoiceRepository. If you recall, a Stub is a Test Double that substitutes for a production component but inputs canned data into the system under test. In our test, we're just checking for that canned data to verify that the InvoiceRepository called our InvoiceRepositoryDataAccessStub instance in the correct way. Priorities In a project with little or no unit tests, it can be overwhelming to begin refactoring the code. There can be the tendency to want to first establish unit tests for the entire code base before refactoring starts. This, of course, is linear thinking. An established code base has been verified to a certain extent. If it's been deployed, the code effectively "works". Attempting to unit test every line of code isn't going to change that fact. It's when we start to change code that we want to verify that our change doesn't have an unwanted side-effect. To this effect, we want to prioritize unit-testing to avoid having unit-testing become the sole focus of the team. I find that the unit-testing priorities when starting out with unit-testing are the same as when a system has had unit tests for some time. The focus should be that any new code should have as much unit-testing code coverage as realistically possible and any code that needs to be refactored should have code coverage as high as realistically possible. The priority here is to ensure that any new code is tested and verified, and accept the fact that existing code has been verified in its own way. If we're not planning on immediately changing certain parts of code, they don't need unit-tests and should be of lower priority. Code coverage Something that often goes hand-in-hand with unit testing is Code Coverage. The goal of code coverage is to get as close to 100% coverage as reasonably possible. Code Coverage is the measure of the percentage of code that is executed (covered) by automated tests. Code coverage is a metric generally used in teams that are performing unit tests on a good portion of their code. Just starting out with unit testing, code coverage is effectively anecdotal. It doesn't tell you much more than you are doing some unit tests. One trap to get into as teams start approaching majority code coverage is to strive for 100% code coverage. This is both problematic and counterproductive. There is some code that is difficult to test and even harder to verify. The work involved to test this code is simply to increase code coverage percentages. I prefer to view the code coverage delta over time. In other words, I concentrate on how the code coverage percentage changes (or doesn't). I want to ensure that it's not going down. If the code coverage percentage is really low (say 25%) then I may want to see it increasing, but not at the risk of supplanting other work.
Read more
  • 0
  • 0
  • 987

article-image-microsoft-visual-studio-2010-improving-class-quality-coupling
Packt
29 Jul 2010
6 min read
Save for later

Microsoft Visual Studio 2010: Improving Class Quality with Coupling

Packt
29 Jul 2010
6 min read
(For more resources on Microsoft products, see here.) Coupling is the degree to which two things are related. Coupling and cohesion go hand in hand. Something that is highly-cohesive generally has low coupling. Coupling is a form of dependency. There are many different types of coupling when we're talking about software design and development. The effort here isn't to make a decoupled design, it's to change the coupling. At some level, one piece of code is coupled to every other piece of code in the system—there is rarely any change you can make to change that. Some code is more highly-coupled to other code and uses the other code directly. Some code is more loosely-coupled and uses other code indirectly. Efforts at refactoring towards a more loosely-coupled design are about the degree to which coupling has been made indirect. Code can be coupled to other code by a shared data format (external coupling). Code can be coupled to other code by the fact that it results in the execution of other code (control coupling). Code can be coupled to other code by the fact that it results in executing other code by way of an abstract interface ( message coupling). Code can be coupled to other code by the fact that they share data, usually in the form of parameters (data coupling ). Code can be coupled to other code by the fact that it has a subclass relationship ( subclass coupling). Code can also be coupled to other code by that fact that it directly references a type's public interface (content coupling ). The direction and degree to which a type is coupled can also help focus our refactoring efforts. Afferent coupling is the degree to which a type is depended upon (inward coupling). Efferent coupling is the degree to which a type depends on other types (outward coupling ). High afferent coupling can indicate that a type has too many responsibilities. It's trying to be everything to everyone and thus being used by everyone. High efferent coupling could indicate a type is very dependant. This becomes an issue when the types the class depends upon are in many different assemblies, suggesting a cohesion issue at the assembly layer. Highly-coupled software is generally accepted to exhibit certain traits, and it can be hard to change. It's like pulling on the thread of a sweater; there are so many dependencies it's impossible to predict how much code will need to be modified in order to make a seemingly simple change. Highly-coupled code is also very rigid. It's hard to move or hard not to duplicate it outside its current context. It carries a lot of baggage (dependencies) with it that need to move with it as a unit. It's one thing to move the code you want to move, it's exponentially harder to move all its dependencies. While good object-oriented design often promotes high cohesion, loosely coupled design and structure can easily fall to the wayside. Refactoring subclass coupling Refactoring subclass coupling involves removing the inheritance relationship between two classes. Refactoring content coupling Content coupling is one class directly referencing another. There are several tactics for refactoring away this coupling. Depending on the situation, one tactic may be more applicable than another. One tactic is to use interface-based design and remove the coupling to the content of the class and replace it with coupling to an interface that the other class now implements. Another tactic is to replace method calls into the other class with delegate invocations. A final tactic is to use events instead of direct method calls. For any particular refactoring, a combination of these tactics may be the best solution. You may find that despite a one-to-one coupling between two classes, it's more appropriate to use a combination of tactics to refactor away the content coupling. Interface-based design If you're already coupled to a particular class, replacing use of that class with an interface and having the other class implement that interface is the easiest way to change the coupling between two classes. This reduces coupling from content coupling to a more loosely coupled message coupling. If the requirements of the other class are very complex or a series of members must come from a single source, using interfaces is often the best solution. Having to hook up several delegates or several events becomes tedious and error prone when a single reference to an object that implements a particular interface is so simple. Imagine if implementing a Windows Form wasn't as simple as deriving from Form and having to register a number of delegates or events. If you find that implementers of the interface would find default or base implementation for them to be useful, implementing that interface may best be done with an abstract class. Our Invoice class is a good example of something that can be more loosely coupled through interface-based design. It currently implements the calculation of grand totals through interface-based design and the strategy pattern. This could have easily been implemented through direct use of a particular class. For example: /// <summary>/// Service to enapsulate calculation of/// grand totals./// </summary>public class InvoiceGrandTotalService{ public float CalculateGrandTotal(float invoiceSubTotal, float invoiceTotalTax) { return invoiceSubTotal + invoiceTotalTax; }}/// <summary>/// Invoice class that uses/// <seealso cref="InvoiceGrandTotalService"/>/// </summary>public class Invoice{ InvoiceGrandTotalService invoiceGrandTotalService = new InvoiceGrandTotalService(); public List<InvoiceLineItem> InvoiceLineItems { get; set; } public Invoice(IEnumerable<InvoiceLineItem> invoiceLineItems) { InvoiceLineItems = new List<InvoiceLineItem>(invoiceLineItems); } public float CalculateGrandTotal(float invoiceSubTotal, float invoiceTotalTax) { return invoiceGrandTotalService.CalculateGrandTotal( invoiceSubTotal, invoiceTotalTax); } //...} In this example, we've created the InvoiceGrandTotalService class that contains the CalculateGrandTotal method. We then instantiate this class in the Invoice class and make reference to it in the CalculateGrandTotal method. We've given away the surprise with this refactoring. We're obviously going to replace direct use of the class with an interface. Since we essentially need a reference to an object right from the start, and to effectively loosen the coupling, we begin refactoring by accepting a reference to an IInvoiceGrandTotalStrategy object in the constructor. We then change our InvoiceGrandTotalService field to an IInvoiceGrandTotalStrategy field and initialize it in the constructor. We finish our refactoring by replacing references from invoiceGrandTotalServcie to invoiceGrandTotalStrategy. The resulting refactoring will look similar to the following: /// <summary>/// Invoice class that uses/// <seealso cref="IInvoiceGrandTotalStrategy"/>/// </summary>public class Invoice{ private IInvoiceGrandTotalStrategy invoiceGrandTotalStrategy; public List<InvoiceLineItem> InvoiceLineItems { get; set; } public Invoice(IEnumerable<InvoiceLineItem> invoiceLineItems, IInvoiceGrandTotalStrategy invoiceGrandTotalStrategy) { InvoiceLineItems = new List<InvoiceLineItem>(invoiceLineItems); this.invoiceGrandTotalStrategy = invoiceGrandTotalStrategy; } public float CalculateGrandTotal(float invoiceSubTotal, float invoiceTotalTax) { return invoiceGrandTotalStrategy.CalculateGrandTotal( invoiceSubTotal, invoiceTotalTax); } //...} If you find that the relationship between the two classes is the invocation of one or two methods that return or update data, you may find that delegates are the best way of refactoring.
Read more
  • 0
  • 0
  • 962

article-image-microsoft-visual-studio-2010-improving-class-quality-cohesion
Packt
29 Jul 2010
12 min read
Save for later

Microsoft Visual Studio 2010: Improving Class Quality with Cohesion

Packt
29 Jul 2010
12 min read
(For more resources on Microsoft products, see here.) Larry Constantine is attributed with the creation of systematic measurement of software quality. In the mid-to-late seventies, Larry Constantine (and Ed Yourdon) attributed several things to the quality of software code. Under the umbrella of structured design, among those attributes of quality software code were cohesion and coupling. At the time they associated quality with generality, flexibility, and reliability. In this article series, we're going to concentrate on generality and flexibility and how cohesion and coupling can be applied to increase code quality. Larry Constantine:http://en.wikipedia.org/wiki/Larry_Constantine Cohesion applies to many different disciplines. Cohesion in physics relates to the force that keeps molecules integrated and united and that makes the molecule what it is. A highly cohesive molecule is one that tends to remain autonomous and not adhere to or blend with other molecules. In geology, cohesion is the strength of substances to resist being broken apart. In linguistics, it's the degree to which text is related. Text whose content relates to the same subject is cohesive. Cohesion in software is very similar to cohesion elsewhere. A cohesive block of code is a block of code that relates well together and has the ability to remain together as a unit. Object-oriented programming brings distinct cohesive abilities. All programming languages have certain cohesive abilities, such as their ability to group code in modules, source files, functions, and so on. A programming language's ability to define physical boundaries enables cohesiveness. A module, for example, defines a specific boundary for which some content is retained and other content is repelled. Code from one module can use code from another module, but only in specific and defined ways—usually independent of language syntax. All code within a module has innate cohesion: their relation amongst themselves as being contained within the module. Any rule, principle, guideline, or practice needs to be implemented thoughtfully. This text isn't a manual on how you must perform your refactoring; it's a description of several types of refactorings and their impetus. By the same token, this text doesn't set out to prove the benefits of any particular rule, principle, guideline, or practice. "Mileage may vary" and incorrect usage will often negate most, if not all, benefits. I'll leave it as an exercise for the reader to find the research that "proves" the benefits of any particular rule, principle, guideline, or practice. This text assumes the generally accepted benefits of various principles and practices, including cohesion, as an indicator of quality. If you decide that the benefits aren't outweighing the costs, it's up to you to decide not to implement that principle. Class cohesion Object-orientation brings extra cohesive abilities to the programmer. The programmer has the ability to relate code together within a class. Other code can use the code within a class, but only through its defined boundaries (the class's methods and properties). In object-oriented design, cohesion is generally much more than simply code contained within a class. Object-oriented cohesiveness goes beyond the physical relation of code within a class and deals with the relation of meaning of the code within a class. Object-oriented language syntax allows the programmer to freely relate code to other code through a class definition, but this doesn't mean that code is cohesive. For example, let's revisit our Invoice class so far. /// <summary>/// Invoice class to encapsulate invoice line items/// and drawing/// </summary>public class Invoice{ private IInvoiceGrandTotalStrategy invoiceGrandTotalStrategy; public Invoice(IEnumerable<InvoiceLineItem> invoiceLineItems, IInvoiceGrandTotalStrategy invoiceGrandTotalStrategy) { InvoiceLineItems = new List<InvoiceLineItem>(invoiceLineItems); this.invoiceGrandTotalStrategy = invoiceGrandTotalStrategy; } private List<InvoiceLineItem> InvoiceLineItems { get; set; } public void GenerateReadableInvoice(Graphics graphics) { graphics.DrawString(HeaderText, HeaderFont, HeaderBrush, HeaderLocation); float invoiceSubTotal = 0; PointF currentLineItemLocation = LineItemLocation; foreach (InvoiceLineItem invoiceLineItem in InvoiceLineItems) { float lineItemSubTotal = CalculateLineItemSubTotal(invoiceLineItem); graphics.DrawString(invoiceLineItem.Description, InvoiceBodyFont, InvoiceBodyBrush, currentLineItemLocation); currentLineItemLocation.Y += InvoiceBodyFont.GetHeight(graphics); invoiceSubTotal += lineItemSubTotal; } float invoiceTotalTax = CalculateInvoiceTotalTax(invoiceSubTotal); float invoiceGrandTotal = invoiceGrandTotalStrategy.CalculateGrandTotal( invoiceSubTotal, invoiceTotalTax); CalculateInvoiceGrandTotal(invoiceSubTotal, invoiceTotalTax); graphics.DrawString(String.Format( "Invoice SubTotal: {0}", invoiceGrandTotal - invoiceTotalTax), InvoiceBodyFont, InvoiceBodyBrush, InvoiceSubTotalLocation); graphics.DrawString(String.Format("Total Tax: {0}", invoiceTotalTax), InvoiceBodyFont, InvoiceBodyBrush, InvoiceTaxLocation); graphics.DrawString(String.Format( "Invoice Grand Total: {0}", invoiceGrandTotal), InvoiceBodyFont, InvoiceBodyBrush, InvoiceGrandTotalLocation); graphics.DrawString(FooterText, FooterFont, FooterBrush, FooterLocation); } public static float CalculateInvoiceGrandTotal( float invoiceSubTotal, float invoiceTotalTax) { float invoiceGrandTotal = invoiceTotalTax + invoiceSubTotal; return invoiceGrandTotal; } public float CalculateInvoiceTotalTax( float invoiceSubTotal) { float invoiceTotalTax = (float)((Decimal)invoiceSubTotal * (Decimal)TaxRate); return invoiceTotalTax; } public static float CalculateLineItemSubTotal( InvoiceLineItem invoiceLineItem) { float lineItemSubTotal = (float)((decimal)(invoiceLineItem.Price - invoiceLineItem.Discount) * (decimal)invoiceLineItem.Quantity); return lineItemSubTotal; } public string HeaderText { get; set; } public Font HeaderFont { get; set; } public Brush HeaderBrush { get; set; } public RectangleF HeaderLocation { get; set; } public string FooterText { get; set; } public Font FooterFont { get; set; } public Brush FooterBrush { get; set; } public RectangleF FooterLocation { get; set; } public float TaxRate { get; set; } public Font InvoiceBodyFont { get; set; } public Brush InvoiceBodyBrush { get; set; } public Point LineItemLocation { get; set; } public RectangleF InvoiceSubTotalLocation { get; set; } public RectangleF InvoiceTaxLocation { get; set; } public RectangleF InvoiceGrandTotalLocation { get; set; }} We have an operational Invoice class. It does some things, and they work. But, our Invoice class isn't very cohesive. The Invoice class has distinct groups of fields. Some are for the state of an invoice and some are for generating a readable invoice. Methods that deal with the behavior and attributes of an invoice don't use the fields that deal with generating a readable invoice. Our Invoice class is implementing two distinct tasks: managing invoice state and generating a readable invoice. The data required to generate a readable invoice (over and above the data shown on an invoice) isn't used by Invoice when not generating a readable invoice. Our Invoice class can be said to have multiple responsibilities: the responsibility of managing state and the responsibility of generating a readable invoice. What makes an invoice an invoice may be fairly stable; we may occasionally need to add, remove, or change fields that store data contained in an invoice. But, the act of displaying a readable invoice may be less stable: it may change quite frequently. Worse still, the act of displaying a readable invoice may depend on the platform it is running on. The Single Responsibility Principle In terms of focusing refactoring efforts towards cohesiveness of a class, the Single Responsibility Principle (SRP) gives us guidance on what a particular class should or should not do. The Single Responsibility Principle states that "there should never be more than one reason for a class to change". In the case of our invoice class there's a couple of reasons why we'd need to change the class: The way an invoice is displayed needs to change. The data that is contained in an invoice needs to change. The stability of each responsibility shouldn't need to depend on the other. That is, any change to the Invoice class affects stability of the whole class. If I often need to change the way an invoice renders a displayable invoice, all of Invoice is instable—including its responsibility to the data an invoice contains. The Single Responsibility Principle's focus is fairly narrow: class responsibility. A novice may simply accept that scope and use it only to focus cohesion efforts at the class level. The fact is that the Single Responsibility Principle is applicable at almost all levels of software design, including method, namespace, module/assembly, and process; that is, a method could implement too much responsibility, the types within an assembly or namespace could have unrelated responsibilities, and the responsibilities of a given process might not be focused effectively. Simply saying "single responsibility" or detailing that something has too many responsibilities is simple. But the actual act of defining what a responsibility is can be very subjective and subtle. Refactoring towards Single Responsibility can take some time and some work to get right. Let's see how we can improve quality through better cohesion and the principle of single responsibility. Refactoring classes with low-cohesion Clearly single responsibility (and the heading of this section) suggests that we should refactor Invoiceinto multiple classes. But, how do we do that given our current scenario? The designer of this class has obviously thought that the functionality of Invoice included rendering a readable invoice, so how do we make a clean separation? Fortunately, the lack of cohesiveness gives us our separation points. What makes an invoice an invoice doesn't include those fields that deal solely with rendering a readable invoice. Fields like HeaderFont, HeaderBrush, HeaderText, HeaderLocation, FooterFont, FooterBrush, FooterText, FooterLocation, InvoiceBodyFont, InvoiceBodyBrush, LineItemLocation, InvoiceBustTotalLocation, InvoiceTaxLocation, and InvoiceGrandTotalLocation all deal with just the rendering responsibility. The Invoice class is modeling a real-world invoice. When you hold an invoice in your hand or view it on the screen, it's already rendered. In the real-world we'd never think that a responsibility of rendering an invoice would be a responsibility of the invoice itself. We know we want to retain our original Invoice class and we want to move the rendering responsibility to a new class. This new class will encapsulate the responsibility of rendering an invoice. Since this new class will take an Invoice object and help another class produce something useful, we can consider this an invoice rendering service. In order to refactor our existing Invoice class to a new Invoice rendering service, we start with a new InvoiceRenderingService class and move the HeaderFont, HeaderBrush, HeaderText, HeaderLocation, FooterFont, FooterBrush, FooterText, FooterLocation, InvoiceBodyFont, InvoiceBodyBrush, LineItemLocation, InvoiceBustTotalLocation, InvoiceTaxLocation, and InvoiceGrandTotalLocation fields to the InvoiceRenderingService. Next, we move the GenerateReadableInvoice method to the InvoiceRenderingService. At this point, we basically have a functional class, but since the InvoiceRenderingService method was on the Invoice classes, the other properties that the GenerateReadableInvoice uses need an Invoice object reference—effectively changing it from "this" to a parameter to the GenerateReadableInvoice method. Since the original Invoice class was never expected to be used externally like this, we need to add a CalculateGrandTotal method that delegates to the invoiceGrandTotalStrategy object. The result is something like the following: /// <summary>/// Encapsulates a service to render an invoice/// to a Graphics device./// </summary>public class InvoiceRenderingService{public void GenerateReadableInvoice(Invoice invoice, Graphics graphics){ graphics.DrawString(HeaderText, HeaderFont, HeaderBrush, HeaderLocation); float invoiceSubTotal = 0; PointF currentLineItemLocation = LineItemLocation; foreach (InvoiceLineItem invoiceLineItem in invoice.InvoiceLineItems) { float lineItemSubTotal = Invoice.CalculateLineItemSubTotal( invoiceLineItem); graphics.DrawString(invoiceLineItem.Description, InvoiceBodyFont, InvoiceBodyBrush, currentLineItemLocation); currentLineItemLocation.Y += InvoiceBodyFont.GetHeight(graphics); invoiceSubTotal += lineItemSubTotal; } float invoiceTotalTax = invoice.CalculateInvoiceTotalTax( invoiceSubTotal); float invoiceGrandTotal = invoice.CalculateGrandTotal( invoiceSubTotal, invoiceTotalTax); Invoice.CalculateInvoiceGrandTotal(invoiceSubTotal, invoiceTotalTax); graphics.DrawString(String.Format( "Invoice SubTotal: {0}", invoiceGrandTotal - invoiceTotalTax), InvoiceBodyFont, InvoiceBodyBrush, InvoiceSubTotalLocation); graphics.DrawString(String.Format("Total Tax: {0}", invoiceTotalTax), InvoiceBodyFont, InvoiceBodyBrush, InvoiceTaxLocation); graphics.DrawString(String.Format( "Invoice Grand Total: {0}", invoiceGrandTotal), InvoiceBodyFont, InvoiceBodyBrush, InvoiceGrandTotalLocation); graphics.DrawString(FooterText, FooterFont, FooterBrush, FooterLocation); } public string HeaderText { get; set; } public Font HeaderFont { get; set; } public Brush HeaderBrush { get; set; } public RectangleF HeaderLocation { get; set; } public string FooterText { get; set; } public Font FooterFont { get; set; } public Brush FooterBrush { get; set; } public RectangleF FooterLocation { get; set; } public Font InvoiceBodyFont { get; set; } public Brush InvoiceBodyBrush { get; set; } public Point LineItemLocation { get; set; } public RectangleF InvoiceSubTotalLocation { get; set; } public RectangleF InvoiceTaxLocation { get; set; } public RectangleF InvoiceGrandTotalLocation { get; set; }} Alternatively, the whole use of invoiceGrandTotalStrategy can be moved into the InvoiceRenderingService—which is a better design decision. Detecting classes with low-cohesion So, we've seen a fairly simple example of making a not-so-cohesive class into two more-cohesive classes; but, one of the tricky parts of refactoring away classes with low cohesion is finding them. How do we find classes with low-cohesion? Fortunately, many people have put time and effort over the years into defining what it means for a class to be cohesive. There have been various metrics researched and created over the years to define cohesion in classes. The most popular metric is Lack of Cohesion of Methods (LCOM) . Lack of Cohesion of Methods measures the degree to which all methods use all fields. The more segregated field usage is amongst methods of a class, the higher the Lack of Cohesion of Methods metric of the class will be. Lack of Cohesion of Methods is a measure of the entire class, so it won't point out where the class is not cohesive or indicate where the responsibilities can be separated. Lack of Cohesion of Methods is a measurement of the degree to which fields are used by all methods of a class. Perfection as defined by Lack of Cohesion of Methods is that every method uses every field in the class. Clearly not every class will do this (and arguably this will hardly ever happen); so, Lack of Cohesion of Methods is a metric, as most metrics are, that requires analysis and thought before attempting to act upon its value. LCOM is a value between 0 and 1, inclusive. A measure of 0 means every method uses every field. The higher the value, the less cohesive the class; the lower the value, the more cohesive the class. A typical acceptable range is 0 to 0.8. But, there's no hard-and-fast definition of specific value that represents cohesive; just because, for example, a class has an LCOM value of 0.9, that doesn't mean it can or should be broken up into multiple classes. Lack of Cohesion of Methods values should be used as a method of prioritizing cohesion refactoring work by focusing on classes with higher LCOM values before other classes (with lower LCOM values). In the case of our Invoice class, it's apparent that its LCOM value does mean it can be split into multiple classes as we detailed in the previous section.
Read more
  • 0
  • 0
  • 866
article-image-new-features-jpa-20
Packt
28 Jul 2010
9 min read
Save for later

New Features in JPA 2.0

Packt
28 Jul 2010
9 min read
(For more resources on Java, see here.) Version 2.0 of the JPA specification introduces some new features to make working with JPA even easier. In the following sections, we discuss some of these new features: Criteria API One of the main additions to JPA in the 2.0 specification is the introduction of the Criteria API. The Criteria API is meant as a complement to the Java Persistence Query Language (JPQL). Although JPQL is very flexible, it has some problems that make working with it more difficult than necessary. For starters, JPQL queries are stored as strings and the compiler has no way of validating JPQL syntax. Additionally, JPQL is not type safe. We could write a JPQL query in which our where clause could have a string value for a numeric property and our code would compile and deploy just fine. To get around the JPQL limitations described in the previous paragraph, the Criteria API was introduced to JPA in version 2.0 of the specification. The Criteria API allows us to write JPA queries programmatically, without having to rely on JPQL. The following code example illustrates how to use the Criteria API in our Java EE 6 applications: package net.ensode.glassfishbook.criteriaapi;import java.io.IOException;import java.io.PrintWriter;import java.util.List;import javax.persistence.EntityManager;import javax.persistence.EntityManagerFactory;import javax.persistence.PersistenceUnit;import javax.persistence.TypedQuery;import ja vax.persistence.criteria.CriteriaBuilder;import javax.persistence.criteria.CriteriaQuery;import javax.persistence.criteria.Path;import javax.persistence.criteria.Predicate;import javax.persistence.criteria.Root;import javax.persistence.metamodel.EntityType;import javax.persistence.metamodel.Metamodel;import javax.persistence.metamodel.SingularAttribute;import javax.servlet.ServletException;import javax.servlet.annotation.WebServlet;import javax.servlet.http.HttpServlet;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@WebServlet(urlPatterns = {"/criteriaapi"})public class CriteriaApiDemoServlet extends HttpServlet{ @PersistenceUnit(unitName = "customerPersistenceUnit") private EntityManagerFactory entityManagerFactory; @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { PrintWriter printWriter = response.getWriter(); List<UsState> matchingStatesList; EntityManager entityManager = entityManagerFactory.createEntityManager(); CriteriaBuilder criteriaBuilder = entityManager.getCriteriaBuilder(); CriteriaQuery<UsState> criteriaQuery = criteriaBuilder.createQuery(UsState.class); Root<UsState> root = criteriaQuery.from(UsState.class); Metamodel metamodel = entityManagerFactory.getMetamodel(); EntityType<UsState> usStateEntityType = metamodel.entity(UsState.class); SingularAttribute<UsState, String> usStateAttribute = usStateEntityType.getDeclaredSingularAttribute("usStateNm", String.class); Path<String> path = root.get(usStateAttribute); Predicate predicate = criteriaBuilder.like(path, "New%"); criteriaQuery = criteriaQuery.where(predicate); TypedQuery typedQuery = entityManager.createQuery(criteriaQuery); matchingStatesList = typedQuery.getResultList(); response.setContentType("text/html"); printWriter.println("The following states match the criteria:<br/>"); for (UsState state : matchingStatesList) { printWriter.println(state.getUsStateNm() + "<br/>"); } }} This example takes advantage of the Criteria APIc. When writing code using the Criteria API, the first thing we need to do is to obtain an instance of a class implementing the javax.persistence.criteria. CriteriaBuilder interface. As we can see in the previous example, we need to obtain said instance by invoking the getCriteriaBuilder() method on our EntityManager. From our CriteriaBuilder implementation, we need to obtain an instance of a class implementing the javax.persistence.criteria.CriteriaQuery interface. We do this by invoking the createQuery() method in our CriteriaBuilder implementation. Notice that CriteriaQuery is generically typed. The generic type argument dictates the type of result that our CriteriaQuery implementation will return upon execution. By taking advantage of generics in this way, the Criteria API allows us to write type safe code. Once we have obtained a CriteriaQuery implementation, from it we can obtain an instance of a class implementing the javax.persistence.criteria.Root interface. The Root implementation dictates what JPA entity we will be querying from. It is analogous to the FROM query in JPQL (and SQL). The next two lines in our example take advantage of another new addition to the JPA specification—the Metamodel API. In order to take advantage of the Metamodel API, we need to obtain an implementation of the javax.persistence. metamodel.Metamodel interface by invoking the getMetamodel() method on our EntityManagerFactory. From our Metamodel implementation, we can obtain a generically typed instance of the javax.persistence.metamodel.EntityType interface. The generic type argument indicates the JPA entity our EntityType implementation corresponds to. EntityType allows us to browse the persistent attributes of our JPA entities at runtime. This is exactly what we do in the next line in our example. In our case, we are getting an instance of SingularAttribute, which maps to a simple, singular attribute in our JPA entity. EntityType has methods to obtain attributes that map to collections, sets, lists, and maps. Obtaining these types of attributes is very similar to obtaining a SingularAttribute, therefore we won't be covering those directly. Refer to the Java EE 6 API documentation at http://java.sun.com/javaee/6/ docs/api/ for more information. As we can see in our example, SingularAttribute contains two generic type arguments. The first argument dictates the JPA entity we are working with and the second one indicates the type of attribute. We obtain our SingularAttribute by invoking the getDeclaredSingularAttribute() method on our EntityType implementation and passing the attribute name (as declared in our JPA entity) as a String. Once we have obtained our SingularAttribute implementation, we need to obtain an import javax.persistence.criteria.Path implementation by invoking the get() method in our Root instance and passing our SingularAttribute as a parameter. In our example, we will get a list of all the "new" states in the United States (that is, all states whose names start with "New"). Of course, this is the job of a "like" condition. We can do this with the Criteria API by invoking the like() method on our CriteriaBuilder implementation. The like() method takes our Path implementation as its first parameter and the value to search for as its second parameter. CriteriaBuilder has a number of methods that are analogous to SQL and JPQL clauses such as equals(), greaterThan(), lessThan(), and(), or(), and so on and so forth (for the complete list, refer to the Java EE 6 documentation at http://java.sun.com/javaee/6/docs/api/). These methods can be combined to create complex queries via the Criteria API. The like() method in CriteriaBuilder returns an implementation of the javax.persistence.criteria.Predicate interface, which we need to pass to the where() method in our CriteriaQuery implementation. This method returns a new instance of CriteriaBuilder which we assign to our criteriaBuilder variable. At this point, we are ready to build our query. When working with the Criteria API, we deal with the javax.persistence.TypedQuery interface, which can be thought of as a type-safe version of the Query interface we use with JPQL. We obtain an instance of TypedQuery by invoking the createQuery() method in EntityManager and passing our CriteriaQuery implementation as a parameter. To obtain our query results as a list, we simply invoke getResultList() on our TypedQuery implementation. It is worth reiterating that the Criteria API is type safe. Therefore, attempting to assign the results of getResultList() to a list of the wrong type would result in a compilation error. After building, packaging, and deploying our code, then pointing the browser to our servlet's URL, we should see all the "New" states displayed in the browser. Bean Validation support Another new feature introduced in JPA 2.0 is support for JSR 303, Bean Validation. Bean Validation support allows us to annotate our JPA entities with Bean Validation annotations. These annotations allow us to easily validate user input and perform data sanitation. Taking advantage of Bean Validation is very simple, all we need to do is annotate our JPA entity fields or getter methods with any of the validation annotations defined in the javax.validation.constraints package. Once our fields are annotated as appropriate, the EntityManager will prevent non-validating data from being persisted. The following code example is a modified version of the Customer JPA entity. It has been modifed to take advantage of Bean Validation in some of its fields. package net.ensode.glassfishbook.jpa.beanvalidation;import java.io.Serializable;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;import javax.validation.constraints.NotNull;import javax.validation.constraints.Size;@Entity@Table(name = "CUSTOMERS")public class Customer implements Serializable{ @Id @Column(name = "CUSTOMER_ID") private Long customerId; @Column(name = "FIRST_NAME") @NotNull @Size(min=2, max=20) private String firstName; @Column(name = "LAST_NAME") @NotNull @Size(min=2, max=20) private String lastName; private String email; public Long getCustomerId() { return customerId; } public void setCustomerId(Long customerId) { this.customerId = customerId; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } public String getFirstName() { return firstName; } public void setFirstName(String firstName) { this.firstName = firstName; } public String getLastName() { return lastName; } public void setLastName(String lastName) { this.lastName = lastName; }} In this example, we used the @NotNull annotation to prevent the firstName and lastName of our entity from being persisted with null values. We also used the @Size annotation to restrict the minimum and maximum length of these fields. This is all we need to do to take advantage of Bean Validation in JPA. If our code attempts to persist or update an instance of our entity that does not pass the declared validation, an exception of type javax.validation.ConstraintViolationException will be thrown and the entity will not be persisted. As we can see, Bean Validation pretty much automates data validation, freeing us from having to manually write validation code. In addition to the two annotations discussed in the previous example, the javax.validation.constraints package contains several additional annotations that we can use to automate validation on our JPA entities. Refer to the Java EE 6 API documentation at http://java.sun.com/javaee/6/docs/api/ for the complete list. Summary In this article, we discussed some new JPA 2.0 features such as the Criteria API that allows us to build JPA queries programmatically, the Metamodel API that allows us to take advantage of Java's type safety when working with JPA, and Bean Validation that allows us to easily validate input by simply annotating our JPA entity fields. Further resources on this subject: Interacting with Databases through the Java Persistence API [article] Setting up GlassFish for JMS and Working with Message Queues [article]
Read more
  • 0
  • 0
  • 2197

article-image-objects-python
Packt
27 Jul 2010
15 min read
Save for later

Objects in Python

Packt
27 Jul 2010
15 min read
(For more resources on Python 3, see here.) Creating Python classes We don't have to write much Python code to realize that Python is a very "clean" language. When we want to do something, we just do it, without having to go through a lot of setup. The ubiquitous, "hello world" in Python, as you've likely seen, is only one line. Similarly, the simplest class in Python 3 looks like this: class MyFirstClass: pass There's our first object-oriented program! The class definition starts with the class keyword. This is followed by a name (of our choice) identifying the class, and is terminated with a colon. The class name must follow standard Python variable naming rules (must start with a letter or underscore, can only be comprised of letters, underscores, or numbers). In addition, the Python style guide (search the web for "PEP 8"), recommends that classes should be named using CamelCase notation (start with a capital letter, any subsequent words should also start with a capital).   The class definition line is followed by the class contents, indented. As with other Python constructs, indentation is used to delimit the classes, rather than braces or brackets as many other languages use. Use four spaces for indentation unless you have a compelling reason not to (such as fitting in with somebody else's code that uses tabs for indents). Any decent programming editor can be configured to insert four spaces whenever the Tab key is pressed. Since our first class doesn't actually do anything, we simply use the pass keyword on the second line to indicate that no further action needs to be taken. We might think there isn't much we can do with this most basic class, but it does allow us to instantiate objects of that class. We can load the class into the Python 3 interpreter so we can play with it interactively. To do this, save the class definition mentioned earlier into a file named first_class.py and then run the command python -i first_class.py. The -i argument tells Python to "run the code and then drop to the interactive interpreter". The following interpreter session demonstrates basic interaction with this class: >>> a = MyFirstClass() >>> b = MyFirstClass() >>> print(a) <__main__.MyFirstClass object at 0xb7b7faec> >>> print(b) <__main__.MyFirstClass object at 0xb7b7fbac> >>> This code instantiates two objects from the new class, named a and b. Creating an instance of a class is a simple matter of typing the class name followed by a pair of parentheses. It looks much like a normal function call, but Python knows we're "calling" a class and not a function, so it understands that its job is to create a new object. When printed, the two objects tell us what class they are and what memory address they live at. Memory addresses aren't used much in Python code, but here,it demonstrates that there are two distinctly different objects involved. Adding attributes Now, we have a basic class, but it's fairly useless. It doesn't contain any data, and it doesn't do anything. What do we have to do to assign an attribute to a given object? It turns out that we don't have to do anything special in the class definition. We can set arbitrary attributes on an instantiated object using the dot notation: class Point: pass p1 = Point() p2 = Point() p1.x = 5 p1.y = 4 p2.x = 3 p2.y = 6 print(p1.x, p1.y) print(p2.x, p2.y) If we run this code, the two print statements at the end tell us the new attribute values on the two objects: 5 4 3 6 This code creates an empty Point class with no data or behaviors. Then it creates two instances of that class and assigns each of those instances x and y coordinates to identify a point in two dimensions. All we need to do to assign a value to an attribute on an object is use the syntax <object>.<attribute>=<value>. This is sometimes referred to as dot notation. The value can be anything: a Python primitive, a built-in data type, another object. It can even be a function or another class! Making it do something Now, having objects with attributes is great, but object-oriented programming is really about the interaction between objects. We're interested in invoking actions that cause things to happen to those attributes. It is time to add behaviors to our classes. Let's model a couple of actions on our Point class. We can start with a method called reset that moves the point to the origin (the origin is the point where x and y are both zero). This is a good introductory action because it doesn't require any parameters: class Point: def reset(self): self.x = 0 self.y = 0 p = Point() p.reset() print(p.x, p.y) That print statement shows us the two zeros on the attributes: 0 0 A method in Python is identical to defining a function. It starts with the keyword def followed by a space and the name of the method. This is followed by a set of parentheses containing the parameter list (we'll discuss the self parameter in just a moment), and terminated with a colon. The next line is indented to contain the statements inside the method. These statements can be arbitrary Python code operating on the object itself and any parameters passed in as the method sees fit. The one difference between methods and normal functions is that all methods have one required argument. This argument is conventionally named self; I've never seen a programmer use any other name for this variable (convention is a very powerful thing). There's nothing stopping you, however, from calling it this or even Martha. The self argument to a method is simply a reference to the object that the method is being invoked on. We can access attributes and methods of that object as if it were any other object. This is exactly what we do inside the reset method when we set the x and y attributes of the self object. Notice that when we call the p.reset() method, we do not have to pass the self argument into it. Python automatically takes care of this for us. It knows we're calling a method on the p object, so it automatically passes that object to the method. However, the method really is just a function that happens to be on a class. Instead of calling the method on the object, we could invoke the function on the class, explicitly passing our object as the self argument: p = Point() Point.reset(p) print(p.x, p.y) The output is the same as the previous example because, internally, the exact same process has occurred. What happens if we forget to include the self argument in our class definition? Python will bail with an error message: >>> class Point: ... def reset(): ... pass ... >>> p = Point() >>> p.reset() Traceback (most recent call last): File "<stdin>", line 1, in <module> TypeError: reset() takes no arguments (1 given) The error message is not as clear as it could be ("You silly fool, you forgot the self argument" would be more informative). Just remember that when you see an error message that indicates missing arguments, the first thing to check is whether you forgot self in the method definition. So how do we pass multiple arguments to a method? Let's add a new method that allows us to move a point to an arbitrary position, not just the origin. We can also include one that accepts another Point object as input and returns the distance between them: import math class Point: def move(self, x, y): self.x = x self.y = y def reset(self): self.move(0, 0) def calculate_distance(self, other_point): return math.sqrt((self.x - other_point.x)**2 +(self.y - other_point.y) **2) # how to use it: point1 = Point() point2 = Point() point1.reset() point2.move(5,0) print(point2.calculate_distance(point1)) assert (point2.calculate_distance(point1) == point1.calculate_distance(point2)) point1.move(3,4) print(point1.calculate_distance(point2)) print(point1.calculate_distance(point1)) The print statements at the end give us the following output: 5.0 4.472135955 0.0 A lot has happened here. The class now has three methods. The move method accepts two arguments, x and y, and sets the values on the self object, much like the old reset method from the previous example. The old reset method now calls move, since a reset is just a move to a specific known location. The calculate_distance method uses the not-too-complex Pythagorean Theorem to calculate the distance between two points. I hope you understand the math (** means squared, and math.sqrt calculates a square root), but it's not a requirement for our current focus: learning how to write methods. The example code at the end shows how to call a method with arguments; simply include the arguments inside the parentheses, and use the same dot notation to access the method. I just picked some random positions to test the methods. The test code calls each method and prints the results on the console. The assert function is a simple test tool; the program will bail if the statement after assert is False (or zero, empty, or None). In this case, we use it to ensure that the distance is the same regardless of which point called the other point's calculate_distance method. Initializing the object If we don't explicitly set the x and y positions on our Point object, either using move or by accessing them directly, we have a broken point with no real position. What will happen when we try to access it? Well, let's just try it and see. "Try it and see" is an extremely useful tool for Python study. Open up your interactive interpreter and type away. The following interactive session shows what happens if we try to access a missing attribute. If you saved the previous example as a file or are using the examples distributed in this article, you can load it into the Python interpreter with the command python -i filename.py. >>> point = Point() >>> point.x = 5 >>> print(point.x) 5 >>> print(point.y) Traceback (most recent call last): File "<stdin>", line 1, in <module> AttributeError: 'Point' object has no attribute 'y' Well, at least it threw a useful exception. You've probably seen them before (especially the ubiquitous SyntaxError, which means you typed something incorrectly!). At this point, simply be aware that it means something went wrong. The output is useful for debugging. In the interactive interpreter it tells us the error occurred at line 1, which is only partially true (in an interactive session, only one line is executed at a time). If we were running a script in a file, it would tell us the exact line number, making it easy to find the offending code. In addition, it tells us the error is an AttributeError, and gives a helpful message telling us what that error means. We can catch and recover from this error, but in this case, it feels like we should have specified some sort of default value. Perhaps every new object should be reset() by default or maybe it would be nice if we could force the user to tell us what those positions should be when they create the object. Most object-oriented programming languages have the concept of a constructor, a special method that creates and initializes the object when it is created. Python is a little different; it has a constructor and an initializer. Normally, the constructor function is rarely ever used unless you're doing something exotic. So we'll start our discussion with the initialization method. The Python initialization method is the same as any other method, except it has a special name: __init__. The leading and trailing double underscores mean, "this is a special method that the Python interpreter will treat as a special case". Never name a function of your own with leading and trailing double underscores. It may mean nothing to Python, but there's always the possibility that the designers of Python will add a function that has a special purpose with that name in the future, and when they do, your code will break. Let's start with an initialization function on our Point class that requires the user to supply x and y coordinates when the Point object is instantiated: class Point: def __init__(self, x, y): self.move(x, y) def move(self, x, y): self.x = x self.y = y def reset(self): self.move(0, 0) # Constructing a Point point = Point(3, 5) print(point.x, point.y) Now, our point can never go without a y coordinate! If we try to construct a point without including the proper initialization parameters, it will fail with a not enough arguments error similar to the one we received earlier when we forgot the self argument. What if we don't want to make those two arguments required? Well then we can use the same syntax Python functions use to provide default arguments. The keyword argument syntax appends an equals sign after each variable name. If the calling object does not provide that argument, then the default argument is used instead; the variables will still be available to the function, but they will have the values specified in the argument list. Here's an example: class Point: def __init__(self, x=0, y=0): self.move(x, y) Most of the time, we put our initialization statements in an __init__ function. But as mentioned earlier, Python has a constructor in addition to its initialization function. You may never need to use the other Python constructor, but it helps to know it exists, so we'll cover it briefly. The constructor function is called __new__ as opposed to __init__, and accepts exactly one argument, the class that is being constructed (it is called before the object is constructed, so there is no self argument). It also has to return the newly created object. This has interesting possibilities when it comes to the complicated art of meta-programming, but is not very useful in day-to-day programming. In practice, you will rarely, if ever, need to use __new__, and __init__ will be sufficient. Explaining yourself Python is an extremely easy-to-read programming language; some might say it is self-documenting. However, when doing object-oriented programming, it is important to write API documentation that clearly summarizes what each object and method does. Keeping documentation up-to-date is difficult; the best way to do it is to write it right into our code. Python supports this through the use of docstrings. Each class, function, or method header can have a standard Python string as the first line following the definition (the line that ends in a colon). This line should be indented the same as the following code. Docstrings are simply Python strings enclosed with apostrophe (') or quote (") characters. Often, docstrings are quite long and span multiple lines (the style guide suggests that line-length should not exceed 80 characters), which can be formatted as multi-line strings, enclosed in matching triple apostrophe (''') or triple quote (""") characters. A docstring should clearly and concisely summarize the purpose of the class or method it is describing. It should explain any parameters whose usage is not immediately obvious, and is also a good place to include short examples of how to use the API. Any caveats or problems an unsuspecting user of the API should be aware of should also be noted. To illustrate the use of docstrings, we will end this part with our completely documented Point class: import math class Point: 'Represents a point in two-dimensional geometric coordinates' def __init__(self, x=0, y=0): '''Initialize the position of a new point. The x and y coordinates can be specified. If they are not, the point defaults to the origin.''' self.move(x, y) def move(self, x, y): "Move the point to a new location in two-dimensional space." self.x = x self.y = y def reset(self): 'Reset the point back to the geometric origin: 0, 0' self.move(0, 0) def calculate_distance(self, other_point): """Calculate the distance from this point to a second point passed as a parameter. This function uses the Pythagorean Theorem to calculate the distance between the two points. The distance is returned as a float.""" return math.sqrt( (self.x - other_point.x)**2 + (self.y – other_point.y)**2) Try typing or loading (remember, it's python -i filename.py) this file into the interactive interpreter. Then enter help(Point)<enter> at the Python prompt. You should see nicely formatted documentation for the class, as shown in the following screenshot:
Read more
  • 0
  • 0
  • 5570